]> granicus.if.org Git - clang/commitdiff
[Sema] Make FunctionType's TSI use unadjusted argument types
authorReid Kleckner <reid@kleckner.net>
Sat, 8 Jun 2013 17:28:56 +0000 (17:28 +0000)
committerReid Kleckner <reid@kleckner.net>
Sat, 8 Jun 2013 17:28:56 +0000 (17:28 +0000)
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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
test/Index/print-type.c
test/Index/print-type.cpp
test/Sema/function-redecl.c

index 324185f0900cacf2b413dd1378b31963af314926..553df517b858cd18329e10d65468c5c5d63f3903 100644 (file)
@@ -1465,7 +1465,7 @@ public:
   ///
   /// \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);
 
index 44ff94e358436ff97ea9c293f7119d993d215c91..384164167db557edd4fbf2fbed42454eea62d9ee 100644 (file)
@@ -4142,6 +4142,21 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
 }
 
 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
index c32df11b66777c72ae461b847087e72bc08ae348..2c5233bce67ba583c0b83f0aa530edd5e279550d 100644 (file)
@@ -1781,8 +1781,10 @@ bool TypeOfExprType::isSugared() const {
 }
 
 QualType TypeOfExprType::desugar() const {
-  if (isSugared())
-    return getUnderlyingExpr()->getType();
+  if (isSugared()) {
+    Expr *E = getUnderlyingExpr();
+    return E->getType();
+  }
   
   return QualType(this, 0);
 }
index e6a89461b4593a57ea39e614f46d1dc374fe9cd1..1db768b28a68be089594444985e5e2b27f0adb40 100644 (file)
@@ -5897,23 +5897,40 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       << 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)) {
+  // 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;
+    }
+  }
+
+  // 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(T,
-                                  ArrayRef<QualType>(FPT->arg_type_begin(),
-                                                     FPT->getNumArgs()),
-                                  EPI);
+      R = Context.getFunctionType(ResultTy, AdjustedParms, EPI);
+    } else {
+      assert(isa<FunctionNoProtoType>(FT));
+      FunctionType::ExtInfo EI = FT->getExtInfo();
+      R = Context.getFunctionNoProtoType(ResultTy, EI);
     }
-    else if (isa<FunctionNoProtoType>(R))
-      R = Context.getFunctionNoProtoType(T);
   }
 
   bool isFriend = false;
@@ -8498,27 +8515,15 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
                                   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,
index e27d627d3ff1937496c84695bdce65df8168b304..977294bd4618e477bc444f93d913636d803387b3 100644 (file)
@@ -1674,7 +1674,7 @@ QualType Sema::BuildFunctionType(QualType T,
   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 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
 
         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.
index 4805f59f3fe048f957e3d1bd1ad7546680a29406..5fc28ab605066d46242ccc1bd61b4990fe25696f 100644 (file)
@@ -11,7 +11,7 @@ int __attribute__((vector_size(16))) x;
 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]
index 49a05fbbdbdfb11bd7d8c07b0b2c7917066c9a51..0f62826225a75a1180881c86403099961df49c6a 100644 (file)
@@ -62,5 +62,5 @@ T tbar(int[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]
index 561f7fae6b90d8c39829b82ef65f51af1347220f..a43dfc3de36a6bb8c85d0d3e069bc2d7e1ef30c5 100644 (file)
@@ -115,6 +115,11 @@ void i0 (unsigned short a0);
 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;