Index: cfe/trunk/include/clang/AST/Type.h =================================================================== --- cfe/trunk/include/clang/AST/Type.h +++ cfe/trunk/include/clang/AST/Type.h @@ -1502,6 +1502,9 @@ unsigned Kind : 8; }; + /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. + /// Only common bits are stored here. Additional uncommon bits are stored + /// in a trailing object after FunctionProtoType. class FunctionTypeBitfields { friend class FunctionProtoType; friend class FunctionType; @@ -1512,6 +1515,11 @@ /// regparm and the calling convention. unsigned ExtInfo : 12; + /// The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; + /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. /// The qualifiers are part of FunctionProtoType because... @@ -1520,10 +1528,23 @@ /// cv-qualifier-seq, [...], are part of the function type. unsigned TypeQuals : 4; - /// The ref-qualifier associated with a \c FunctionProtoType. - /// - /// This is a value of type \c RefQualifierKind. - unsigned RefQualifier : 2; + /// The number of parameters this function has, not counting '...'. + /// According to [implimits] 8 bits should be enough here but this is + /// somewhat easy to exceed with metaprogramming and so we would like to + /// keep NumParams as wide as reasonably possible. + unsigned NumParams : 16; + + /// The type of exception specification this function has. + unsigned ExceptionSpecType : 4; + + /// Whether this function has extended parameter information. + unsigned HasExtParameterInfos : 1; + + /// Whether the function is variadic. + unsigned Variadic : 1; + + /// Whether this function has a trailing return type. + unsigned HasTrailingReturn : 1; }; class ObjCObjectTypeBitfields { @@ -3331,6 +3352,92 @@ QualType ResultType; public: + /// Interesting information about a specific parameter that can't simply + /// be reflected in parameter's type. This is only used by FunctionProtoType + /// but is in FunctionType to make this class available during the + /// specification of the bases of FunctionProtoType. + /// + /// It makes sense to model language features this way when there's some + /// sort of parameter-specific override (such as an attribute) that + /// affects how the function is called. For example, the ARC ns_consumed + /// attribute changes whether a parameter is passed at +0 (the default) + /// or +1 (ns_consumed). This must be reflected in the function type, + /// but isn't really a change to the parameter type. + /// + /// One serious disadvantage of modelling language features this way is + /// that they generally do not work with language features that attempt + /// to destructure types. For example, template argument deduction will + /// not be able to match a parameter declared as + /// T (*)(U) + /// against an argument of type + /// void (*)(__attribute__((ns_consumed)) id) + /// because the substitution of T=void, U=id into the former will + /// not produce the latter. + class ExtParameterInfo { + enum { + ABIMask = 0x0F, + IsConsumed = 0x10, + HasPassObjSize = 0x20, + IsNoEscape = 0x40, + }; + unsigned char Data = 0; + + public: + ExtParameterInfo() = default; + + /// Return the ABI treatment of this parameter. + ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } + ExtParameterInfo withABI(ParameterABI kind) const { + ExtParameterInfo copy = *this; + copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); + return copy; + } + + /// 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; + } + + bool hasPassObjectSize() const { return Data & HasPassObjSize; } + ExtParameterInfo withHasPassObjectSize() const { + ExtParameterInfo Copy = *this; + Copy.Data |= HasPassObjSize; + return Copy; + } + + bool isNoEscape() const { return Data & IsNoEscape; } + ExtParameterInfo withIsNoEscape(bool NoEscape) const { + ExtParameterInfo Copy = *this; + if (NoEscape) + Copy.Data |= IsNoEscape; + else + Copy.Data &= ~IsNoEscape; + 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; + } + }; + /// A class which abstracts out some details necessary for /// making a call. /// @@ -3465,6 +3572,22 @@ } }; + /// A simple holder for a QualType representing a type in an + /// exception specification. Unfortunately needed by FunctionProtoType + /// because TrailingObjects cannot handle repeated types. + struct ExceptionType { QualType Type; }; + + /// A simple holder for various uncommon bits which do not fit in + /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the + /// alignment of subsequent objects in TrailingObjects. You must update + /// hasExtraBitfields in FunctionProtoType after adding extra data here. + struct alignas(void *) FunctionTypeExtraBitfields { + /// The number of types in the exception specification. + /// A whole unsigned is not needed here and according to + /// [implimits] 8 bits would be enough here. + unsigned NumExceptionType; + }; + protected: FunctionType(TypeClass tc, QualType res, QualType Canonical, bool Dependent, @@ -3544,104 +3667,61 @@ /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no -/// parameters, not as having a single void parameter. Such a type can have an -/// exception specification, but this specification is not part of the canonical -/// type. -class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { -public: - /// Interesting information about a specific parameter that can't simply - /// be reflected in parameter's type. - /// - /// It makes sense to model language features this way when there's some - /// sort of parameter-specific override (such as an attribute) that - /// affects how the function is called. For example, the ARC ns_consumed - /// attribute changes whether a parameter is passed at +0 (the default) - /// or +1 (ns_consumed). This must be reflected in the function type, - /// but isn't really a change to the parameter type. - /// - /// One serious disadvantage of modelling language features this way is - /// that they generally do not work with language features that attempt - /// to destructure types. For example, template argument deduction will - /// not be able to match a parameter declared as - /// T (*)(U) - /// against an argument of type - /// void (*)(__attribute__((ns_consumed)) id) - /// because the substitution of T=void, U=id into the former will - /// not produce the latter. - class ExtParameterInfo { - enum { - ABIMask = 0x0F, - IsConsumed = 0x10, - HasPassObjSize = 0x20, - IsNoEscape = 0x40, - }; - unsigned char Data = 0; - - public: - ExtParameterInfo() = default; - - /// Return the ABI treatment of this parameter. - ParameterABI getABI() const { - return ParameterABI(Data & ABIMask); - } - ExtParameterInfo withABI(ParameterABI kind) const { - ExtParameterInfo copy = *this; - copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); - return copy; - } - - /// 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; - } - - bool hasPassObjectSize() const { - return Data & HasPassObjSize; - } - ExtParameterInfo withHasPassObjectSize() const { - ExtParameterInfo Copy = *this; - Copy.Data |= HasPassObjSize; - return Copy; - } - - bool isNoEscape() const { - return Data & IsNoEscape; - } - - ExtParameterInfo withIsNoEscape(bool NoEscape) const { - ExtParameterInfo Copy = *this; - if (NoEscape) - Copy.Data |= IsNoEscape; - else - Copy.Data &= ~IsNoEscape; - return Copy; - } - - unsigned char getOpaqueValue() const { return Data; } - static ExtParameterInfo getFromOpaqueValue(unsigned char data) { - ExtParameterInfo result; - result.Data = data; - return result; - } +/// parameters, not as having a single void parameter. Such a type can have +/// an exception specification, but this specification is not part of the +/// canonical type. FunctionProtoType has several trailing objects, some of +/// which optional. For more information about the trailing objects see +/// the first comment inside FunctionProtoType. +class FunctionProtoType final + : public FunctionType, + public llvm::FoldingSetNode, + private llvm::TrailingObjects< + FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, + FunctionType::ExceptionType, Expr *, FunctionDecl *, + FunctionType::ExtParameterInfo> { + friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; - friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data == rhs.Data; - } - friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { - return lhs.Data != rhs.Data; - } - }; + // FunctionProtoType is followed by several trailing objects, some of + // which optional. They are in order: + // + // * An array of getNumParams() QualType holding the parameter types. + // Always present. Note that for the vast majority of FunctionProtoType, + // these will be the only trailing objects. + // + // * Optionally if some extra data is stored in FunctionTypeExtraBitfields + // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): + // a single FunctionTypeExtraBitfields. Present if and only if + // hasExtraBitfields() is true. + // + // * Optionally exactly one of: + // * an array of getNumExceptions() ExceptionType, + // * a single Expr *, + // * a pair of FunctionDecl *, + // * a single FunctionDecl * + // used to store information about the various types of exception + // specification. See getExceptionSpecSize for the details. + // + // * Optionally an array of getNumParams() ExtParameterInfo holding + // an ExtParameterInfo for each of the parameters. Present if and + // only if hasExtParameterInfos() is true. + // + // The optional FunctionTypeExtraBitfields has to be before the data + // related to the exception specification since it contains the number + // of exception types. + // + // We 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. +public: + /// Holds information about the various types of exception specification. + /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is + /// used to group together the various bits of information about the + /// exception specification. struct ExceptionSpecInfo { /// The kind of exception specification this is. ExceptionSpecificationType Type = EST_None; @@ -3665,7 +3745,9 @@ ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; - /// Extra information about a function prototype. + /// Extra information about a function prototype. ExtProtoInfo is not + /// stored as such in FunctionProtoType but is used to group together + /// the various bits of extra information about a function prototype. struct ExtProtoInfo { FunctionType::ExtInfo ExtInfo; bool Variadic : 1; @@ -3675,21 +3757,42 @@ ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; - ExtProtoInfo() - : Variadic(false), HasTrailingReturn(false) {} + ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} - ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &O) { + ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { ExtProtoInfo Result(*this); - Result.ExceptionSpec = O; + Result.ExceptionSpec = ESI; return Result; } }; private: - friend class ASTContext; // ASTContext creates these. + unsigned numTrailingObjects(OverloadToken) const { + return getNumParams(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasExtraBitfields(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumExceptionType; + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumExprPtr; + } + + unsigned numTrailingObjects(OverloadToken) const { + return getExceptionSpecSize().NumFunctionDeclPtr; + } + + unsigned numTrailingObjects(OverloadToken) const { + return hasExtParameterInfos() ? getNumParams() : 0; + } /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. @@ -3705,88 +3808,67 @@ FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi); - /// The number of parameters this function has, not counting '...'. - unsigned NumParams : 15; - - /// The number of types in the exception spec, if any. - unsigned NumExceptions : 9; - - /// The type of exception specification this function has. - unsigned ExceptionSpecType : 4; - - /// Whether this function has extended parameter information. - unsigned HasExtParameterInfos : 1; - - /// Whether the function is variadic. - unsigned Variadic : 1; - - /// Whether this function has a trailing return type. - unsigned HasTrailingReturn : 1; - - // ParamInfo - There is an variable size array after the class in memory that - // holds the parameter types. - - // Exceptions - There is another variable size array after ArgInfo that - // holds the exception types. - - // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing - // to the expression in the noexcept() specifier. - - // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may - // be a pair of FunctionDecl* pointing to the function which should be used to - // instantiate this function type's exception specification, and the function - // from which it should be instantiated. - - // 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. - - const ExtParameterInfo *getExtParameterInfosBuffer() const { - assert(hasExtParameterInfos()); - - // Find the end of the exception specification. - const auto *ptr = reinterpret_cast(exception_begin()); - ptr += getExceptionSpecSize(); - - return reinterpret_cast(ptr); - } + /// This struct is returned by getExceptionSpecSize and is used to + /// translate an ExceptionSpecificationType to the number and kind + /// of trailing objects related to the exception specification. + struct ExceptionSpecSizeHolder { + unsigned NumExceptionType; + unsigned NumExprPtr; + unsigned NumFunctionDeclPtr; + }; - static size_t getExceptionSpecSize(ExceptionSpecificationType EST, - unsigned NumExceptions) { + /// Return the number and kind of trailing objects + /// related to the exception specification. + static ExceptionSpecSizeHolder + getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { switch (EST) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_Unparsed: - return 0; + return {0, 0, 0}; case EST_Dynamic: - return NumExceptions * sizeof(QualType); + return {NumExceptions, 0, 0}; case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: - return sizeof(Expr *); + return {0, 1, 0}; case EST_Uninstantiated: - return 2 * sizeof(FunctionDecl *); + return {0, 0, 2}; case EST_Unevaluated: - return sizeof(FunctionDecl *); + return {0, 0, 1}; } llvm_unreachable("bad exception specification kind"); } - size_t getExceptionSpecSize() const { + + /// Return the number and kind of trailing objects + /// related to the exception specification. + ExceptionSpecSizeHolder getExceptionSpecSize() const { return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); } + /// Whether the trailing FunctionTypeExtraBitfields is present. + static bool hasExtraBitfields(ExceptionSpecificationType EST) { + // If the exception spec type is EST_Dynamic then we have > 0 exception + // types and the exact number is stored in FunctionTypeExtraBitfields. + return EST == EST_Dynamic; + } + + /// Whether the trailing FunctionTypeExtraBitfields is present. + bool hasExtraBitfields() const { + return hasExtraBitfields(getExceptionSpecType()); + } + public: - unsigned getNumParams() const { return NumParams; } + unsigned getNumParams() const { return FunctionTypeBits.NumParams; } QualType getParamType(unsigned i) const { - assert(i < NumParams && "invalid parameter index"); + assert(i < getNumParams() && "invalid parameter index"); return param_type_begin()[i]; } @@ -3812,20 +3894,18 @@ } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } - if (hasExtParameterInfos()) - EPI.ExtParameterInfos = getExtParameterInfosBuffer(); + EPI.ExtParameterInfos = getExtParameterInfosOrNull(); return EPI; } /// Get the kind of exception specification on this function. ExceptionSpecificationType getExceptionSpecType() const { - return static_cast(ExceptionSpecType); + return static_cast( + FunctionTypeBits.ExceptionSpecType); } /// Return whether this function has any kind of exception spec. - bool hasExceptionSpec() const { - return getExceptionSpecType() != EST_None; - } + bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { @@ -3844,16 +3924,26 @@ /// spec. bool hasInstantiationDependentExceptionSpec() const; - unsigned getNumExceptions() const { return NumExceptions; } + /// Return the number of types in the exception specification. + unsigned getNumExceptions() const { + return getExceptionSpecType() == EST_Dynamic + ? getTrailingObjects() + ->NumExceptionType + : 0; + } + + /// Return the ith exception type, where 0 <= i < getNumExceptions(). QualType getExceptionType(unsigned i) const { - assert(i < NumExceptions && "Invalid exception number!"); + assert(i < getNumExceptions() && "Invalid exception number!"); return exception_begin()[i]; } + + /// Return the expression inside noexcept(expression), or a null pointer + /// if there is none (because the exception spec is not of this form). Expr *getNoexceptExpr() const { if (!isComputedNoexcept(getExceptionSpecType())) return nullptr; - // NoexceptExpr sits where the arguments end. - return *reinterpret_cast(param_type_end()); + return *getTrailingObjects(); } /// If this function type has an exception specification which hasn't @@ -3864,7 +3954,7 @@ if (getExceptionSpecType() != EST_Uninstantiated && getExceptionSpecType() != EST_Unevaluated) return nullptr; - return reinterpret_cast(param_type_end())[0]; + return getTrailingObjects()[0]; } /// If this function type has an uninstantiated exception @@ -3874,7 +3964,7 @@ FunctionDecl *getExceptionSpecTemplate() const { if (getExceptionSpecType() != EST_Uninstantiated) return nullptr; - return reinterpret_cast(param_type_end())[1]; + return getTrailingObjects()[1]; } /// Determine whether this function type has a non-throwing exception @@ -3885,11 +3975,11 @@ /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. bool isNothrow(bool ResultIfDependent = false) const { - return ResultIfDependent ? canThrow() != CT_Can - : canThrow() == CT_Cannot; + return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; } - bool isVariadic() const { return Variadic; } + /// Whether this function prototype is variadic. + bool isVariadic() const { return FunctionTypeBits.Variadic; } /// Determines whether this function prototype contains a /// parameter pack at the end. @@ -3899,7 +3989,8 @@ /// function. bool isTemplateVariadic() const; - bool hasTrailingReturn() const { return HasTrailingReturn; } + /// Whether this function prototype has a trailing return type. + bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } @@ -3916,11 +4007,11 @@ } param_type_iterator param_type_begin() const { - return reinterpret_cast(this+1); + return getTrailingObjects(); } param_type_iterator param_type_end() const { - return param_type_begin() + NumParams; + return param_type_begin() + getNumParams(); } using exception_iterator = const QualType *; @@ -3930,22 +4021,23 @@ } exception_iterator exception_begin() const { - // exceptions begin where arguments end - return param_type_end(); + return reinterpret_cast( + getTrailingObjects()); } exception_iterator exception_end() const { - if (getExceptionSpecType() != EST_Dynamic) - return exception_begin(); - return exception_begin() + NumExceptions; + return exception_begin() + getNumExceptions(); } /// Is there any interesting extra information for any of the parameters /// of this function type? - bool hasExtParameterInfos() const { return HasExtParameterInfos; } + bool hasExtParameterInfos() const { + return FunctionTypeBits.HasExtParameterInfos; + } + ArrayRef getExtParameterInfos() const { assert(hasExtParameterInfos()); - return ArrayRef(getExtParameterInfosBuffer(), + return ArrayRef(getTrailingObjects(), getNumParams()); } @@ -3955,27 +4047,27 @@ const ExtParameterInfo *getExtParameterInfosOrNull() const { if (!hasExtParameterInfos()) return nullptr; - return getExtParameterInfosBuffer(); + return getTrailingObjects(); } ExtParameterInfo getExtParameterInfo(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I]; + return getTrailingObjects()[I]; return ExtParameterInfo(); } ParameterABI getParameterABI(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I].getABI(); + return getTrailingObjects()[I].getABI(); return ParameterABI::Ordinary; } bool isParamConsumed(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) - return getExtParameterInfosBuffer()[I].isConsumed(); + return getTrailingObjects()[I].isConsumed(); return false; } Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -3697,30 +3697,19 @@ assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - // FunctionProtoType objects are allocated with extra bytes after - // them for three variable size arrays at the end: - // - parameter types - // - exception types - // - 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) + - FunctionProtoType::getExceptionSpecSize( - EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); - - // 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); - } + // Compute the needed size to hold this FunctionProtoType and the + // various trailing objects. + auto ESH = FunctionProtoType::getExceptionSpecSize( + EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); + size_t Size = FunctionProtoType::totalSizeToAlloc< + QualType, FunctionType::FunctionTypeExtraBitfields, + FunctionType::ExceptionType, Expr *, FunctionDecl *, + FunctionProtoType::ExtParameterInfo>( + NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type), + ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr, + EPI.ExtParameterInfos ? NumArgs : 0); - auto *FTP = (FunctionProtoType *) Allocate(Size, TypeAlignment); + auto *FTP = (FunctionProtoType *)Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); Index: cfe/trunk/lib/AST/Type.cpp =================================================================== --- cfe/trunk/lib/AST/Type.cpp +++ cfe/trunk/lib/AST/Type.cpp @@ -2833,24 +2833,28 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi) - : FunctionType(FunctionProto, result, canonical, - result->isDependentType(), + : FunctionType(FunctionProto, result, canonical, result->isDependentType(), result->isInstantiationDependentType(), result->isVariablyModifiedType(), - result->containsUnexpandedParameterPack(), epi.ExtInfo), - NumParams(params.size()), - NumExceptions(epi.ExceptionSpec.Exceptions.size()), - ExceptionSpecType(epi.ExceptionSpec.Type), - HasExtParameterInfos(epi.ExtParameterInfos != nullptr), - Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) { - assert(NumParams == params.size() && "function has too many parameters"); - + result->containsUnexpandedParameterPack(), epi.ExtInfo) { FunctionTypeBits.TypeQuals = epi.TypeQuals; FunctionTypeBits.RefQualifier = epi.RefQualifier; + FunctionTypeBits.NumParams = params.size(); + assert(getNumParams() == params.size() && "NumParams overflow!"); + FunctionTypeBits.ExceptionSpecType = epi.ExceptionSpec.Type; + FunctionTypeBits.HasExtParameterInfos = !!epi.ExtParameterInfos; + FunctionTypeBits.Variadic = epi.Variadic; + FunctionTypeBits.HasTrailingReturn = epi.HasTrailingReturn; + + // Fill in the extra trailing bitfields if present. + if (hasExtraBitfields(epi.ExceptionSpec.Type)) { + auto &ExtraBits = *getTrailingObjects(); + ExtraBits.NumExceptionType = epi.ExceptionSpec.Exceptions.size(); + } // Fill in the trailing argument array. - auto *argSlot = reinterpret_cast(this+1); - for (unsigned i = 0; i != NumParams; ++i) { + auto *argSlot = getTrailingObjects(); + for (unsigned i = 0; i != getNumParams(); ++i) { if (params[i]->isDependentType()) setDependent(); else if (params[i]->isInstantiationDependentType()) @@ -2862,9 +2866,11 @@ argSlot[i] = params[i]; } + // Fill in the exception type array if present. if (getExceptionSpecType() == EST_Dynamic) { - // Fill in the exception array. - QualType *exnSlot = argSlot + NumParams; + assert(hasExtraBitfields() && "missing trailing extra bitfields!"); + auto *exnSlot = + reinterpret_cast(getTrailingObjects()); unsigned I = 0; for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) { // Note that, before C++17, a dependent exception specification does @@ -2878,14 +2884,15 @@ exnSlot[I++] = ExceptionType; } - } else if (isComputedNoexcept(getExceptionSpecType())) { + } + // Fill in the Expr * in the exception specification if present. + else if (isComputedNoexcept(getExceptionSpecType())) { assert(epi.ExceptionSpec.NoexceptExpr && "computed noexcept with no expr"); assert((getExceptionSpecType() == EST_DependentNoexcept) == epi.ExceptionSpec.NoexceptExpr->isValueDependent()); // Store the noexcept expression and context. - auto **noexSlot = reinterpret_cast(argSlot + NumParams); - *noexSlot = epi.ExceptionSpec.NoexceptExpr; + *getTrailingObjects() = epi.ExceptionSpec.NoexceptExpr; if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) @@ -2893,10 +2900,12 @@ if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); - } else if (getExceptionSpecType() == EST_Uninstantiated) { + } + // Fill in the FunctionDecl * in the exception specification if present. + else if (getExceptionSpecType() == EST_Uninstantiated) { // Store the function decl from which we will resolve our // exception specification. - auto **slot = reinterpret_cast(argSlot + NumParams); + auto **slot = getTrailingObjects(); slot[0] = epi.ExceptionSpec.SourceDecl; slot[1] = epi.ExceptionSpec.SourceTemplate; // This exception specification doesn't make the type dependent, because @@ -2904,7 +2913,7 @@ } else if (getExceptionSpecType() == EST_Unevaluated) { // Store the function decl from which we will resolve our // exception specification. - auto **slot = reinterpret_cast(argSlot + NumParams); + auto **slot = getTrailingObjects(); slot[0] = epi.ExceptionSpec.SourceDecl; } @@ -2921,10 +2930,10 @@ setDependent(); } + // Fill in the extra parameter info if present. if (epi.ExtParameterInfos) { - auto *extParamInfos = - const_cast(getExtParameterInfosBuffer()); - for (unsigned i = 0; i != NumParams; ++i) + auto *extParamInfos = getTrailingObjects(); + for (unsigned i = 0; i != getNumParams(); ++i) extParamInfos[i] = epi.ExtParameterInfos[i]; } } @@ -2970,7 +2979,7 @@ case EST_Dynamic: // A dynamic exception specification is throwing unless every exception // type is an (unexpanded) pack expansion type. - for (unsigned I = 0, N = NumExceptions; I != N; ++I) + for (unsigned I = 0; I != getNumExceptions(); ++I) if (!getExceptionType(I)->getAs()) return CT_Can; return CT_Dependent; @@ -3045,8 +3054,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, getReturnType(), param_type_begin(), NumParams, getExtProtoInfo(), - Ctx, isCanonicalUnqualified()); + Profile(ID, getReturnType(), param_type_begin(), getNumParams(), + getExtProtoInfo(), Ctx, isCanonicalUnqualified()); } QualType TypedefType::desugar() const {