r262278 - Generalize the consumed-parameter array on FunctionProtoType
John McCall via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 29 16:49:02 PST 2016
Author: rjmccall
Date: Mon Feb 29 18:49:02 2016
New Revision: 262278
URL: http://llvm.org/viewvc/llvm-project?rev=262278&view=rev
Log:
Generalize the consumed-parameter array on FunctionProtoType
to allow arbitrary data to be associated with a parameter.
Also, fix a bug where we apparently haven't been serializing
this information for the last N years.
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/lib/Serialization/ASTWriter.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Feb 29 18:49:02 2016
@@ -2260,7 +2260,7 @@ public:
QualType mergeObjCGCQualifiers(QualType, QualType);
- bool FunctionTypesMatchOnNSConsumedAttrs(
+ bool doFunctionTypesMatchOnExtParameterInfos(
const FunctionProtoType *FromFunctionType,
const FunctionProtoType *ToFunctionType);
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Feb 29 18:49:02 2016
@@ -3040,6 +3040,44 @@ public:
/// type.
class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
public:
+ class ExtParameterInfo {
+ enum {
+ IsConsumed = 0x01,
+ };
+ unsigned char Data;
+ public:
+ ExtParameterInfo() : Data(0) {}
+
+ /// Is this parameter considered "consumed" by Objective-C ARC?
+ /// Consumed parameters must have retainable object type.
+ bool isConsumed() const {
+ return (Data & IsConsumed);
+ }
+ ExtParameterInfo withIsConsumed(bool consumed) const {
+ ExtParameterInfo copy = *this;
+ if (consumed) {
+ copy.Data |= IsConsumed;
+ } else {
+ copy.Data &= ~IsConsumed;
+ }
+ return copy;
+ }
+
+ unsigned char getOpaqueValue() const { return Data; }
+ static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
+ ExtParameterInfo result;
+ result.Data = data;
+ return result;
+ }
+
+ friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data == rhs.Data;
+ }
+ friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data != rhs.Data;
+ }
+ };
+
struct ExceptionSpecInfo {
ExceptionSpecInfo()
: Type(EST_None), NoexceptExpr(nullptr),
@@ -3067,11 +3105,11 @@ public:
struct ExtProtoInfo {
ExtProtoInfo()
: Variadic(false), HasTrailingReturn(false), TypeQuals(0),
- RefQualifier(RQ_None), ConsumedParameters(nullptr) {}
+ RefQualifier(RQ_None), ExtParameterInfos(nullptr) {}
ExtProtoInfo(CallingConv CC)
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
- RefQualifier(RQ_None), ConsumedParameters(nullptr) {}
+ RefQualifier(RQ_None), ExtParameterInfos(nullptr) {}
ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) {
ExtProtoInfo Result(*this);
@@ -3085,7 +3123,7 @@ public:
unsigned char TypeQuals;
RefQualifierKind RefQualifier;
ExceptionSpecInfo ExceptionSpec;
- const bool *ConsumedParameters;
+ const ExtParameterInfo *ExtParameterInfos;
};
private:
@@ -3112,8 +3150,8 @@ private:
/// The type of exception specification this function has.
unsigned ExceptionSpecType : 4;
- /// Whether this function has any consumed parameters.
- unsigned HasAnyConsumedParams : 1;
+ /// Whether this function has extended parameter information.
+ unsigned HasExtParameterInfos : 1;
/// Whether the function is variadic.
unsigned Variadic : 1;
@@ -3135,25 +3173,36 @@ private:
// instantiate this function type's exception specification, and the function
// from which it should be instantiated.
- // ConsumedParameters - A variable size array, following Exceptions
- // and of length NumParams, holding flags indicating which parameters
- // are consumed. This only appears if HasAnyConsumedParams is true.
+ // ExtParameterInfos - A variable size array, following the exception
+ // specification and of length NumParams, holding an ExtParameterInfo
+ // for each of the parameters. This only appears if HasExtParameterInfos
+ // is true.
friend class ASTContext; // ASTContext creates these.
- const bool *getConsumedParamsBuffer() const {
- assert(hasAnyConsumedParams());
-
- // Find the end of the exceptions.
- Expr *const *eh_end = reinterpret_cast<Expr *const *>(exception_end());
- if (getExceptionSpecType() == EST_ComputedNoexcept)
- eh_end += 1; // NoexceptExpr
- // The memory layout of these types isn't handled here, so
- // hopefully this is never called for them?
- assert(getExceptionSpecType() != EST_Uninstantiated &&
- getExceptionSpecType() != EST_Unevaluated);
+ const ExtParameterInfo *getExtParameterInfosBuffer() const {
+ assert(hasExtParameterInfos());
- return reinterpret_cast<const bool*>(eh_end);
+ // Find the end of the exception specification.
+ const char *ptr = reinterpret_cast<const char *>(exception_begin());
+ ptr += getExceptionSpecSize();
+
+ return reinterpret_cast<const ExtParameterInfo *>(ptr);
+ }
+
+ size_t getExceptionSpecSize() const {
+ switch (getExceptionSpecType()) {
+ case EST_None: return 0;
+ case EST_DynamicNone: return 0;
+ case EST_MSAny: return 0;
+ case EST_BasicNoexcept: return 0;
+ case EST_Unparsed: return 0;
+ case EST_Dynamic: return getNumExceptions() * sizeof(QualType);
+ case EST_ComputedNoexcept: return sizeof(Expr*);
+ case EST_Uninstantiated: return 2 * sizeof(FunctionDecl*);
+ case EST_Unevaluated: return sizeof(FunctionDecl*);
+ }
+ llvm_unreachable("bad exception specification kind");
}
public:
@@ -3184,8 +3233,8 @@ public:
} else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl();
}
- if (hasAnyConsumedParams())
- EPI.ConsumedParameters = getConsumedParamsBuffer();
+ if (hasExtParameterInfos())
+ EPI.ExtParameterInfos = getExtParameterInfosBuffer();
return EPI;
}
@@ -3300,11 +3349,24 @@ public:
return exception_begin() + NumExceptions;
}
- bool hasAnyConsumedParams() const { return HasAnyConsumedParams; }
+ bool hasExtParameterInfos() const { return HasExtParameterInfos; }
+ ArrayRef<ExtParameterInfo> getExtParameterInfos() const {
+ assert(hasExtParameterInfos());
+ return ArrayRef<ExtParameterInfo>(getExtParameterInfosBuffer(),
+ getNumParams());
+ }
+
+ ExtParameterInfo getExtParameterInfo(unsigned I) const {
+ assert(I < getNumParams() && "parameter index out of range");
+ if (hasExtParameterInfos())
+ return getExtParameterInfosBuffer()[I];
+ return ExtParameterInfo();
+ }
+
bool isParamConsumed(unsigned I) const {
assert(I < getNumParams() && "parameter index out of range");
- if (hasAnyConsumedParams())
- return getConsumedParamsBuffer()[I];
+ if (hasExtParameterInfos())
+ return getExtParameterInfosBuffer()[I].isConsumed();
return false;
}
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Feb 29 18:49:02 2016
@@ -2992,13 +2992,18 @@ ASTContext::getDependentSizedExtVectorTy
return QualType(New, 0);
}
+/// \brief Determine whether \p T is canonical as the result type of a function.
+static bool isCanonicalResultType(QualType T) {
+ return T.isCanonical() &&
+ (T.getObjCLifetime() == Qualifiers::OCL_None ||
+ T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone);
+}
+
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv CallConv = Info.getCC();
-
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -3010,8 +3015,9 @@ ASTContext::getFunctionNoProtoType(QualT
return QualType(FT, 0);
QualType Canonical;
- if (!ResultTy.isCanonical()) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
+ if (!isCanonicalResultType(ResultTy)) {
+ Canonical =
+ getFunctionNoProtoType(getCanonicalFunctionResultType(ResultTy), Info);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -3019,21 +3025,13 @@ ASTContext::getFunctionNoProtoType(QualT
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
- FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv);
FunctionNoProtoType *New = new (*this, TypeAlignment)
- FunctionNoProtoType(ResultTy, Canonical, newInfo);
+ FunctionNoProtoType(ResultTy, Canonical, Info);
Types.push_back(New);
FunctionNoProtoTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
-/// \brief Determine whether \p T is canonical as the result type of a function.
-static bool isCanonicalResultType(QualType T) {
- return T.isCanonical() &&
- (T.getObjCLifetime() == Qualifiers::OCL_None ||
- T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone);
-}
-
CanQualType
ASTContext::getCanonicalFunctionResultType(QualType ResultType) const {
CanQualType CanResultType = getCanonicalType(ResultType);
@@ -3100,12 +3098,13 @@ ASTContext::getFunctionType(QualType Res
// them for three variable size arrays at the end:
// - parameter types
// - exception types
- // - consumed-arguments flags
+ // - extended parameter information
// Instead of the exception types, there could be a noexcept
// expression, or information used to resolve the exception
// specification.
size_t Size = sizeof(FunctionProtoType) +
NumArgs * sizeof(QualType);
+
if (EPI.ExceptionSpec.Type == EST_Dynamic) {
Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType);
} else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) {
@@ -3115,8 +3114,16 @@ ASTContext::getFunctionType(QualType Res
} else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
Size += sizeof(FunctionDecl*);
}
- if (EPI.ConsumedParameters)
- Size += NumArgs * sizeof(bool);
+
+ // Put the ExtParameterInfos last. If all were equal, it would make
+ // more sense to put these before the exception specification, because
+ // it's much easier to skip past them compared to the elaborate switch
+ // required to skip the exception specification. However, all is not
+ // equal; ExtParameterInfos are used to model very uncommon features,
+ // and it's better not to burden the more common paths.
+ if (EPI.ExtParameterInfos) {
+ Size += NumArgs * sizeof(FunctionProtoType::ExtParameterInfo);
+ }
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
@@ -7489,8 +7496,7 @@ QualType ASTContext::mergeFunctionTypes(
if (lproto->getTypeQuals() != rproto->getTypeQuals())
return QualType();
- if (LangOpts.ObjCAutoRefCount &&
- !FunctionTypesMatchOnNSConsumedAttrs(rproto, lproto))
+ if (!doFunctionTypesMatchOnExtParameterInfos(rproto, lproto))
return QualType();
// Check parameter type compatibility
@@ -7878,21 +7884,26 @@ QualType ASTContext::mergeTypes(QualType
llvm_unreachable("Invalid Type::Class!");
}
-bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
- const FunctionProtoType *FromFunctionType,
- const FunctionProtoType *ToFunctionType) {
- if (FromFunctionType->hasAnyConsumedParams() !=
- ToFunctionType->hasAnyConsumedParams())
+bool ASTContext::doFunctionTypesMatchOnExtParameterInfos(
+ const FunctionProtoType *firstFnType,
+ const FunctionProtoType *secondFnType) {
+ // Fast path: if the first type doesn't have ext parameter infos,
+ // we match if and only if they second type also doesn't have them.
+ if (!firstFnType->hasExtParameterInfos())
+ return !secondFnType->hasExtParameterInfos();
+
+ // Otherwise, we can only match if the second type has them.
+ if (!secondFnType->hasExtParameterInfos())
return false;
- FunctionProtoType::ExtProtoInfo FromEPI =
- FromFunctionType->getExtProtoInfo();
- FunctionProtoType::ExtProtoInfo ToEPI =
- ToFunctionType->getExtProtoInfo();
- if (FromEPI.ConsumedParameters && ToEPI.ConsumedParameters)
- for (unsigned i = 0, n = FromFunctionType->getNumParams(); i != n; ++i) {
- if (FromEPI.ConsumedParameters[i] != ToEPI.ConsumedParameters[i])
- return false;
- }
+
+ auto firstEPI = firstFnType->getExtParameterInfos();
+ auto secondEPI = secondFnType->getExtParameterInfos();
+ assert(firstEPI.size() == secondEPI.size());
+
+ for (size_t i = 0, n = firstEPI.size(); i != n; ++i) {
+ if (firstEPI[i] != secondEPI[i])
+ return false;
+ }
return true;
}
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Feb 29 18:49:02 2016
@@ -2671,7 +2671,7 @@ FunctionProtoType::FunctionProtoType(Qua
NumParams(params.size()),
NumExceptions(epi.ExceptionSpec.Exceptions.size()),
ExceptionSpecType(epi.ExceptionSpec.Type),
- HasAnyConsumedParams(epi.ConsumedParameters != nullptr),
+ HasExtParameterInfos(epi.ExtParameterInfos != nullptr),
Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) {
assert(NumParams == params.size() && "function has too many parameters");
@@ -2737,10 +2737,11 @@ FunctionProtoType::FunctionProtoType(Qua
slot[0] = epi.ExceptionSpec.SourceDecl;
}
- if (epi.ConsumedParameters) {
- bool *consumedParams = const_cast<bool *>(getConsumedParamsBuffer());
+ if (epi.ExtParameterInfos) {
+ ExtParameterInfo *extParamInfos =
+ const_cast<ExtParameterInfo *>(getExtParameterInfosBuffer());
for (unsigned i = 0; i != NumParams; ++i)
- consumedParams[i] = epi.ConsumedParameters[i];
+ extParamInfos[i] = epi.ExtParameterInfos[i];
}
}
@@ -2860,9 +2861,9 @@ void FunctionProtoType::Profile(llvm::Fo
epi.ExceptionSpec.Type == EST_Unevaluated) {
ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
}
- if (epi.ConsumedParameters) {
+ if (epi.ExtParameterInfos) {
for (unsigned i = 0; i != NumParams; ++i)
- ID.AddBoolean(epi.ConsumedParameters[i]);
+ ID.AddInteger(epi.ExtParameterInfos[i].getOpaqueValue());
}
epi.ExtInfo.Profile(ID);
ID.AddBoolean(epi.HasTrailingReturn);
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Feb 29 18:49:02 2016
@@ -2541,9 +2541,8 @@ bool Sema::IsBlockPointerConversion(Qual
// Argument types are too different. Abort.
return false;
}
- if (LangOpts.ObjCAutoRefCount &&
- !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType,
- ToFunctionType))
+ if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
+ ToFunctionType))
return false;
ConvertedType = ToType;
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Feb 29 18:49:02 2016
@@ -3982,9 +3982,9 @@ static TypeSourceInfo *GetFullTypeForDec
SmallVector<QualType, 16> ParamTys;
ParamTys.reserve(FTI.NumParams);
- SmallVector<bool, 16> ConsumedParameters;
- ConsumedParameters.reserve(FTI.NumParams);
- bool HasAnyConsumedParameters = false;
+ SmallVector<FunctionProtoType::ExtParameterInfo, 16>
+ ExtParameterInfos(FTI.NumParams);
+ bool HasAnyInterestingExtParameterInfos = false;
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
@@ -4042,17 +4042,16 @@ static TypeSourceInfo *GetFullTypeForDec
}
}
- if (LangOpts.ObjCAutoRefCount) {
- bool Consumed = Param->hasAttr<NSConsumedAttr>();
- ConsumedParameters.push_back(Consumed);
- HasAnyConsumedParameters |= Consumed;
+ if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withIsConsumed(true);
+ HasAnyInterestingExtParameterInfos = true;
}
ParamTys.push_back(ParamTy);
}
- if (HasAnyConsumedParameters)
- EPI.ConsumedParameters = ConsumedParameters.data();
+ if (HasAnyInterestingExtParameterInfos)
+ EPI.ExtParameterInfos = ExtParameterInfos.data();
SmallVector<QualType, 4> Exceptions;
SmallVector<ParsedType, 2> DynamicExceptions;
@@ -5950,18 +5949,28 @@ static bool handleFunctionTypeAttr(TypeP
}
}
- // Diagnose use of callee-cleanup calling convention on variadic functions.
+ // Diagnose use of variadic functions with calling conventions that
+ // don't support them (e.g. because they're callee-cleanup).
+ // We delay warning about this on unprototyped function declarations
+ // until after redeclaration checking, just in case we pick up a
+ // prototype that way. And apparently we also "delay" warning about
+ // unprototyped function types in general, despite not necessarily having
+ // much ability to diagnose it later.
if (!supportsVariadicCall(CC)) {
const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
if (FnP && FnP->isVariadic()) {
unsigned DiagID = diag::err_cconv_varargs;
+
// stdcall and fastcall are ignored with a warning for GCC and MS
// compatibility.
- if (CC == CC_X86StdCall || CC == CC_X86FastCall)
+ bool IsInvalid = true;
+ if (CC == CC_X86StdCall || CC == CC_X86FastCall) {
DiagID = diag::warn_cconv_varargs;
+ IsInvalid = false;
+ }
S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC);
- attr.setInvalid();
+ if (IsInvalid) attr.setInvalid();
return true;
}
}
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Feb 29 18:49:02 2016
@@ -5387,6 +5387,17 @@ QualType ASTReader::readTypeRecord(unsig
for (unsigned I = 0; I != NumParams; ++I)
ParamTypes.push_back(readType(*Loc.F, Record, Idx));
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> ExtParameterInfos;
+ if (Idx != Record.size()) {
+ for (unsigned I = 0; I != NumParams; ++I)
+ ExtParameterInfos.push_back(
+ FunctionProtoType::ExtParameterInfo
+ ::getFromOpaqueValue(Record[Idx++]));
+ EPI.ExtParameterInfos = ExtParameterInfos.data();
+ }
+
+ assert(Idx == Record.size());
+
return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=262278&r1=262277&r2=262278&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Feb 29 18:49:02 2016
@@ -239,8 +239,14 @@ void ASTTypeWriter::VisitFunctionProtoTy
for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
Writer.AddTypeRef(T->getParamType(I), Record);
+ if (T->hasExtParameterInfos()) {
+ for (unsigned I = 0, N = T->getNumParams(); I != N; ++I)
+ Record.push_back(T->getExtParameterInfo(I).getOpaqueValue());
+ }
+
if (T->isVariadic() || T->hasTrailingReturn() || T->getTypeQuals() ||
- T->getRefQualifier() || T->getExceptionSpecType() != EST_None)
+ T->getRefQualifier() || T->getExceptionSpecType() != EST_None ||
+ T->hasExtParameterInfos())
AbbrevToUse = 0;
Code = TYPE_FUNCTION_PROTO;
More information about the cfe-commits
mailing list