forked from OSchip/llvm-project
[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 llvm-svn: 183614
This commit is contained in:
parent
7dae9ce021
commit
4c124ffd5b
|
@ -1465,7 +1465,7 @@ public:
|
||||||
///
|
///
|
||||||
/// \pre Neither type.ObjCLifetime() nor \p lifetime may be \c OCL_None.
|
/// \pre Neither type.ObjCLifetime() nor \p lifetime may be \c OCL_None.
|
||||||
QualType getLifetimeQualifiedType(QualType type,
|
QualType getLifetimeQualifiedType(QualType type,
|
||||||
Qualifiers::ObjCLifetime lifetime) {
|
Qualifiers::ObjCLifetime lifetime) const {
|
||||||
assert(type.getObjCLifetime() == Qualifiers::OCL_None);
|
assert(type.getObjCLifetime() == Qualifiers::OCL_None);
|
||||||
assert(lifetime != Qualifiers::OCL_None);
|
assert(lifetime != Qualifiers::OCL_None);
|
||||||
|
|
||||||
|
|
|
@ -4142,6 +4142,21 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType ASTContext::getAdjustedParameterType(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:
|
// C99 6.7.5.3p7:
|
||||||
// A declaration of a parameter as "array of type" shall be
|
// A declaration of a parameter as "array of type" shall be
|
||||||
// adjusted to "qualified pointer to type", where the type
|
// adjusted to "qualified pointer to type", where the type
|
||||||
|
|
|
@ -1781,8 +1781,10 @@ bool TypeOfExprType::isSugared() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType TypeOfExprType::desugar() const {
|
QualType TypeOfExprType::desugar() const {
|
||||||
if (isSugared())
|
if (isSugared()) {
|
||||||
return getUnderlyingExpr()->getType();
|
Expr *E = getUnderlyingExpr();
|
||||||
|
return E->getType();
|
||||||
|
}
|
||||||
|
|
||||||
return QualType(this, 0);
|
return QualType(this, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5897,23 +5897,40 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
<< DeclSpec::getSpecifierName(TSCS);
|
<< DeclSpec::getSpecifierName(TSCS);
|
||||||
|
|
||||||
// Do not allow returning a objc interface by-value.
|
// 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(D.getIdentifierLoc(),
|
||||||
diag::err_object_cannot_be_passed_returned_by_value) << 0
|
diag::err_object_cannot_be_passed_returned_by_value) << 0 << ResultTy
|
||||||
<< R->getAs<FunctionType>()->getResultType()
|
<< FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
|
||||||
<< FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
|
ResultTy = Context.getObjCObjectPointerType(ResultTy);
|
||||||
|
NeedsAdjustment = true;
|
||||||
|
}
|
||||||
|
|
||||||
QualType T = R->getAs<FunctionType>()->getResultType();
|
// Adjust parameter types from the type as written.
|
||||||
T = Context.getObjCObjectPointerType(T);
|
SmallVector<QualType, 16> AdjustedParms;
|
||||||
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
|
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT);
|
||||||
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
|
if (FPT) {
|
||||||
R = Context.getFunctionType(T,
|
for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(),
|
||||||
ArrayRef<QualType>(FPT->arg_type_begin(),
|
E = FPT->arg_type_end(); I != E; ++I) {
|
||||||
FPT->getNumArgs()),
|
AdjustedParms.push_back(Context.getAdjustedParameterType(*I));
|
||||||
EPI);
|
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(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;
|
bool isFriend = false;
|
||||||
|
@ -8498,27 +8515,15 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
|
||||||
SourceLocation NameLoc, IdentifierInfo *Name,
|
SourceLocation NameLoc, IdentifierInfo *Name,
|
||||||
QualType T, TypeSourceInfo *TSInfo,
|
QualType T, TypeSourceInfo *TSInfo,
|
||||||
VarDecl::StorageClass StorageClass) {
|
VarDecl::StorageClass StorageClass) {
|
||||||
// In ARC, infer a lifetime qualifier for appropriate parameter types.
|
// Diagnose non-const parameter arrays of ARC types.
|
||||||
if (getLangOpts().ObjCAutoRefCount &&
|
if (getLangOpts().ObjCAutoRefCount &&
|
||||||
T.getObjCLifetime() == Qualifiers::OCL_None &&
|
T.getObjCLifetime() == Qualifiers::OCL_None &&
|
||||||
T->isObjCLifetimeType()) {
|
T->isObjCLifetimeType() &&
|
||||||
|
T->isArrayType() &&
|
||||||
Qualifiers::ObjCLifetime lifetime;
|
!T.isConstQualified()) {
|
||||||
|
DelayedDiagnostics.add(
|
||||||
// Special cases for arrays:
|
sema::DelayedDiagnostic::makeForbiddenType(
|
||||||
// - if it's const, use __unsafe_unretained
|
|
||||||
// - otherwise, it's an error
|
|
||||||
if (T->isArrayType()) {
|
|
||||||
if (!T.isConstQualified()) {
|
|
||||||
DelayedDiagnostics.add(
|
|
||||||
sema::DelayedDiagnostic::makeForbiddenType(
|
|
||||||
NameLoc, diag::err_arc_array_param_no_ownership, T, false));
|
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,
|
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
|
||||||
|
|
|
@ -1674,7 +1674,7 @@ QualType Sema::BuildFunctionType(QualType T,
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
|
for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
|
||||||
// FIXME: Loc is too inprecise here, should use proper locations for args.
|
// 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()) {
|
if (ParamType->isVoidType()) {
|
||||||
Diag(Loc, diag::err_param_with_void_type);
|
Diag(Loc, diag::err_param_with_void_type);
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
@ -2798,13 +2798,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
|
|
||||||
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
|
for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
|
||||||
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param);
|
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?");
|
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
|
// 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
|
// function with no other parameters (C99 6.7.5.3p10). We record
|
||||||
// int(void) as a FunctionProtoType with an empty argument list.
|
// int(void) as a FunctionProtoType with an empty argument list.
|
||||||
|
|
|
@ -11,7 +11,7 @@ int __attribute__((vector_size(16))) x;
|
||||||
typedef int __attribute__((vector_size(16))) int4_t;
|
typedef int __attribute__((vector_size(16))) int4_t;
|
||||||
|
|
||||||
// RUN: c-index-test -test-print-type %s | FileCheck %s
|
// 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=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
|
||||||
// CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [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]
|
// CHECK: ParmDecl=z:3:33 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
|
||||||
|
|
|
@ -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: 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: 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: 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]
|
// CHECK: ParmDecl=:30:11 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
|
||||||
|
|
|
@ -115,6 +115,11 @@ void i0 (unsigned short a0);
|
||||||
extern __typeof (i0) i1;
|
extern __typeof (i0) i1;
|
||||||
extern __typeof (i1) 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 a();
|
||||||
typedef int a2(int*);
|
typedef int a2(int*);
|
||||||
a x;
|
a x;
|
||||||
|
|
Loading…
Reference in New Issue