From 63c9a92a805394c1ca9e4a5fd8afb3acbb918d03 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Sat, 8 Jun 2013 17:28:56 +0000 Subject: [PATCH] [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 --- include/clang/AST/ASTContext.h | 2 +- lib/AST/ASTContext.cpp | 15 ++++++++ lib/AST/Type.cpp | 6 ++- lib/Sema/SemaDecl.cpp | 67 ++++++++++++++++++---------------- lib/Sema/SemaType.cpp | 10 ++--- test/Index/print-type.c | 2 +- test/Index/print-type.cpp | 2 +- test/Sema/function-redecl.c | 5 +++ 8 files changed, 67 insertions(+), 42 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 324185f090..553df517b8 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 44ff94e358..384164167d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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 diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index c32df11b66..2c5233bce6 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e6a89461b4..1db768b28a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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()->getResultType()->isObjCObjectType()) { + bool NeedsAdjustment = false; + const FunctionType *FT = R->castAs(); + QualType ResultTy = FT->getResultType(); + if (ResultTy->isObjCObjectType()) { Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs()->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()->getResultType(); - T = Context.getObjCObjectPointerType(T); - if (const FunctionProtoType *FPT = dyn_cast(R)) { + // Adjust parameter types from the type as written. + SmallVector AdjustedParms; + const FunctionProtoType *FPT = dyn_cast(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(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI); + R = Context.getFunctionType(ResultTy, AdjustedParms, EPI); + } else { + assert(isa(FT)); + FunctionType::ExtInfo EI = FT->getExtInfo(); + R = Context.getFunctionNoProtoType(ResultTy, EI); } - else if (isa(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, diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e27d627d3f..977294bd46 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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(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 4805f59f3f..5fc28ab605 100644 --- a/test/Index/print-type.c +++ b/test/Index/print-type.c @@ -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] diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp index 49a05fbbdb..0f62826225 100644 --- a/test/Index/print-type.cpp +++ b/test/Index/print-type.cpp @@ -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] diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c index 561f7fae6b..a43dfc3de3 100644 --- a/test/Sema/function-redecl.c +++ b/test/Sema/function-redecl.c @@ -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; -- 2.40.0