forked from OSchip/llvm-project
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. llvm-svn: 262278
This commit is contained in:
parent
6d0c8a036e
commit
18afab762a
|
@ -2260,7 +2260,7 @@ public:
|
|||
|
||||
QualType mergeObjCGCQualifiers(QualType, QualType);
|
||||
|
||||
bool FunctionTypesMatchOnNSConsumedAttrs(
|
||||
bool doFunctionTypesMatchOnExtParameterInfos(
|
||||
const FunctionProtoType *FromFunctionType,
|
||||
const FunctionProtoType *ToFunctionType);
|
||||
|
||||
|
|
|
@ -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());
|
||||
const ExtParameterInfo *getExtParameterInfosBuffer() const {
|
||||
assert(hasExtParameterInfos());
|
||||
|
||||
// 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);
|
||||
// Find the end of the exception specification.
|
||||
const char *ptr = reinterpret_cast<const char *>(exception_begin());
|
||||
ptr += getExceptionSpecSize();
|
||||
|
||||
return reinterpret_cast<const bool*>(eh_end);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2992,13 +2992,18 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
|
|||
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(QualType ResultTy,
|
|||
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(QualType ResultTy,
|
|||
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 ResultTy, ArrayRef<QualType> ArgArray,
|
|||
// 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 ResultTy, ArrayRef<QualType> ArgArray,
|
|||
} 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(QualType lhs, QualType rhs,
|
|||
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 LHS, QualType RHS,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2671,7 +2671,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
|||
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(QualType result, ArrayRef<QualType> params,
|
|||
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::FoldingSetNodeID &ID, QualType Result,
|
|||
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);
|
||||
|
|
|
@ -2541,9 +2541,8 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
|
|||
// Argument types are too different. Abort.
|
||||
return false;
|
||||
}
|
||||
if (LangOpts.ObjCAutoRefCount &&
|
||||
!Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType,
|
||||
ToFunctionType))
|
||||
if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
|
||||
ToFunctionType))
|
||||
return false;
|
||||
|
||||
ConvertedType = ToType;
|
||||
|
|
|
@ -3982,9 +3982,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
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 *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
}
|
||||
}
|
||||
|
||||
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(TypeProcessingState &state,
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5387,6 +5387,17 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -239,8 +239,14 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) {
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue