[Sema] Make FunctionType's TSI use unadjusted argument types

This helps preserve the type-as-written in the AST, which we need for
MSVC mangling.  In particular, we need to preserve the types of array
parameters in function pointer types.

The essence of this change is:
-  QualType ArgTy = Param->getType();
+  QualType ArgTy = Param->getTypeSourceInfo()->getType();

... followed by the adjustment in ActOnFunctionDeclarator().

Differential Revision: http://llvm-reviews.chandlerc.com/D883

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183614 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 324185f0..553df51 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -1465,7 +1465,7 @@
   ///
   /// \pre Neither type.ObjCLifetime() nor \p lifetime may be \c OCL_None.
   QualType getLifetimeQualifiedType(QualType type,
-                                    Qualifiers::ObjCLifetime lifetime) {
+                                    Qualifiers::ObjCLifetime lifetime) const {
     assert(type.getObjCLifetime() == Qualifiers::OCL_None);
     assert(lifetime != Qualifiers::OCL_None);
 
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 44ff94e..3841641 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4142,6 +4142,21 @@
 }
 
 QualType ASTContext::getAdjustedParameterType(QualType T) const {
+  // In ARC, infer a lifetime qualifier for appropriate parameter types.
+  if (getLangOpts().ObjCAutoRefCount &&
+      T.getObjCLifetime() == Qualifiers::OCL_None &&
+      T->isObjCLifetimeType()) {
+    // Special cases for arrays:
+    //   - if it's const, use __unsafe_unretained
+    //   - otherwise, it's an error
+    Qualifiers::ObjCLifetime lifetime;
+    if (T->isArrayType())
+      lifetime = Qualifiers::OCL_ExplicitNone;
+    else
+      lifetime = T->getObjCARCImplicitLifetime();
+    T = getLifetimeQualifiedType(T, lifetime);
+  }
+
   // C99 6.7.5.3p7:
   //   A declaration of a parameter as "array of type" shall be
   //   adjusted to "qualified pointer to type", where the type
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index c32df11..2c5233b 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1781,8 +1781,10 @@
 }
 
 QualType TypeOfExprType::desugar() const {
-  if (isSugared())
-    return getUnderlyingExpr()->getType();
+  if (isSugared()) {
+    Expr *E = getUnderlyingExpr();
+    return E->getType();
+  }
   
   return QualType(this, 0);
 }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e6a8946..1db768b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5897,23 +5897,40 @@
       << DeclSpec::getSpecifierName(TSCS);
 
   // Do not allow returning a objc interface by-value.
-  if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
+  bool NeedsAdjustment = false;
+  const FunctionType *FT = R->castAs<FunctionType>();
+  QualType ResultTy = FT->getResultType();
+  if (ResultTy->isObjCObjectType()) {
     Diag(D.getIdentifierLoc(),
-         diag::err_object_cannot_be_passed_returned_by_value) << 0
-    << R->getAs<FunctionType>()->getResultType()
-    << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
+         diag::err_object_cannot_be_passed_returned_by_value) << 0 << ResultTy
+        << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
+    ResultTy = Context.getObjCObjectPointerType(ResultTy);
+    NeedsAdjustment = true;
+  }
 
-    QualType T = R->getAs<FunctionType>()->getResultType();
-    T = Context.getObjCObjectPointerType(T);
-    if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
-      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
-      R = Context.getFunctionType(T,
-                                  ArrayRef<QualType>(FPT->arg_type_begin(),
-                                                     FPT->getNumArgs()),
-                                  EPI);
+  // Adjust parameter types from the type as written.
+  SmallVector<QualType, 16> AdjustedParms;
+  const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT);
+  if (FPT) {
+    for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
+         E = FPT->arg_type_end(); I != E; ++I) {
+      AdjustedParms.push_back(Context.getAdjustedParameterType(*I));
+      if (AdjustedParms.back() != *I)
+        NeedsAdjustment = true;
     }
-    else if (isa<FunctionNoProtoType>(R))
-      R = Context.getFunctionNoProtoType(T);
+  }
+
+  // Skip the type recreation if it isn't needed, for performance and to avoid
+  // prematurely desugaring things like typedefs and __typeofs.
+  if (NeedsAdjustment) {
+    if (FPT) {
+      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+      R = Context.getFunctionType(ResultTy, AdjustedParms, EPI);
+    } else {
+      assert(isa<FunctionNoProtoType>(FT));
+      FunctionType::ExtInfo EI = FT->getExtInfo();
+      R = Context.getFunctionNoProtoType(ResultTy, EI);
+    }
   }
 
   bool isFriend = false;
@@ -8498,27 +8515,15 @@
                                   SourceLocation NameLoc, IdentifierInfo *Name,
                                   QualType T, TypeSourceInfo *TSInfo,
                                   VarDecl::StorageClass StorageClass) {
-  // In ARC, infer a lifetime qualifier for appropriate parameter types.
+  // Diagnose non-const parameter arrays of ARC types.
   if (getLangOpts().ObjCAutoRefCount &&
       T.getObjCLifetime() == Qualifiers::OCL_None &&
-      T->isObjCLifetimeType()) {
-
-    Qualifiers::ObjCLifetime lifetime;
-
-    // Special cases for arrays:
-    //   - if it's const, use __unsafe_unretained
-    //   - otherwise, it's an error
-    if (T->isArrayType()) {
-      if (!T.isConstQualified()) {
-        DelayedDiagnostics.add(
-            sema::DelayedDiagnostic::makeForbiddenType(
+      T->isObjCLifetimeType() &&
+      T->isArrayType() &&
+      !T.isConstQualified()) {
+    DelayedDiagnostics.add(
+        sema::DelayedDiagnostic::makeForbiddenType(
             NameLoc, diag::err_arc_array_param_no_ownership, T, false));
-      }
-      lifetime = Qualifiers::OCL_ExplicitNone;
-    } else {
-      lifetime = T->getObjCARCImplicitLifetime();
-    }
-    T = Context.getLifetimeQualifiedType(T, lifetime);
   }
 
   ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index e27d627..977294b 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1674,7 +1674,7 @@
   bool Invalid = false;
   for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
     // FIXME: Loc is too inprecise here, should use proper locations for args.
-    QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
+    QualType ParamType = ParamTypes[Idx];
     if (ParamType->isVoidType()) {
       Diag(Loc, diag::err_param_with_void_type);
       Invalid = true;
@@ -2798,13 +2798,11 @@
 
         for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
           ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
-          QualType ArgTy = Param->getType();
+          // Get the type as written.  It will be adjusted later in
+          // ActOnFunctionDeclarator().
+          QualType ArgTy = Param->getTypeSourceInfo()->getType();
           assert(!ArgTy.isNull() && "Couldn't parse type?");
 
-          // Adjust the parameter type.
-          assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) &&
-                 "Unadjusted type?");
-
           // Look for 'void'.  void is allowed only as a single argument to a
           // function with no other parameters (C99 6.7.5.3p10).  We record
           // int(void) as a FunctionProtoType with an empty argument list.
diff --git a/test/Index/print-type.c b/test/Index/print-type.c
index 4805f59..5fc28ab 100644
--- a/test/Index/print-type.c
+++ b/test/Index/print-type.c
@@ -11,7 +11,7 @@
 typedef int __attribute__((vector_size(16))) int4_t;
 
 // RUN: c-index-test -test-print-type %s | FileCheck %s
-// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int *, void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int [5]] [ConstantArray] [void (*)(int)] [Pointer]] [isPOD=0]
+// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int [5], void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int [5]] [ConstantArray] [void (*)(int)] [Pointer]] [isPOD=0]
 // CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
 // CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [typekind=Pointer] [isPOD=1]
 // CHECK: ParmDecl=z:3:33 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index 49a05fb..0f62826 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -62,5 +62,5 @@
 // CHECK: TypedefDecl=ArrayType:20:15 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
 // CHECK: FunctionTemplate=tbar:27:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
 // CHECK: TemplateTypeParameter=T:26:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
-// CHECK: FunctionTemplate=tbar:30:3 [type=T (int *)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: FunctionTemplate=tbar:30:3 [type=T (int [5])] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int *)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
 // CHECK: ParmDecl=:30:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 561f7fa..a43dfc3 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -115,6 +115,11 @@
 extern __typeof (i0) i1;
 extern __typeof (i1) i1;
 
+// Try __typeof with a parameter that needs adjustment.
+void j0 (int a0[1], ...);
+extern __typeof (j0) j1;
+extern __typeof (j1) j1;
+
 typedef int a();
 typedef int a2(int*);
 a x;