Hi rsmith,
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().
http://llvm-reviews.chandlerc.com/D883
Files:
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: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1457,7 +1457,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);
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -4141,6 +4141,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
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -1781,8 +1781,15 @@
}
QualType TypeOfExprType::desugar() const {
- if (isSugared())
- return getUnderlyingExpr()->getType();
+ if (isSugared()) {
+ Expr *E = getUnderlyingExpr();
+ // In C, due to C99 DR 361, vararg functions decay to no prototype
+ // functions. When used with __typeof, we explicity unwrap the decl to get
+ // its undecayed type. This is similar to what gcc does.
+ if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParens()))
+ return DR->getDecl()->getType();
+ return E->getType();
+ }
return QualType(this, 0);
}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5893,23 +5893,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)) {
+ // 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;
@@ -8494,27 +8511,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,
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ 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 adusted 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: test/Index/print-type.c
===================================================================
--- test/Index/print-type.c
+++ 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]
Index: test/Index/print-type.cpp
===================================================================
--- test/Index/print-type.cpp
+++ 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]
Index: test/Sema/function-redecl.c
===================================================================
--- test/Sema/function-redecl.c
+++ 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;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits