This revision was automatically updated to reflect the committed changes.
Closed by commit rL343579: [AST] Pack the bit-fields of FunctionProtoType into 
Type. (authored by brunoricci, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D52738?vs=167777&id=167922#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D52738

Files:
  cfe/trunk/include/clang/AST/Type.h
  cfe/trunk/lib/AST/ASTContext.cpp
  cfe/trunk/lib/AST/Type.cpp

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,18 +1515,36 @@
     /// 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...
     ///
     /// C++ 8.3.5p4: The return type, the parameter type list and the
     /// 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<QualType>) const {
+    return getNumParams();
+  }
+
+  unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
+    return hasExtraBitfields();
+  }
+
+  unsigned numTrailingObjects(OverloadToken<ExceptionType>) const {
+    return getExceptionSpecSize().NumExceptionType;
+  }
+
+  unsigned numTrailingObjects(OverloadToken<Expr *>) const {
+    return getExceptionSpecSize().NumExprPtr;
+  }
+
+  unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const {
+    return getExceptionSpecSize().NumFunctionDeclPtr;
+  }
+
+  unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) 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<QualType> 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<const char *>(exception_begin());
-    ptr += getExceptionSpecSize();
-
-    return reinterpret_cast<const ExtParameterInfo *>(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<ExceptionSpecificationType>(ExceptionSpecType);
+    return static_cast<ExceptionSpecificationType>(
+        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<FunctionTypeExtraBitfields>()
+                     ->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<Expr *const *>(param_type_end());
+    return *getTrailingObjects<Expr *>();
   }
 
   /// 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<FunctionDecl *const *>(param_type_end())[0];
+    return getTrailingObjects<FunctionDecl *>()[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<FunctionDecl *const *>(param_type_end())[1];
+    return getTrailingObjects<FunctionDecl *>()[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<const QualType *>(this+1);
+    return getTrailingObjects<QualType>();
   }
 
   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<exception_iterator>(
+        getTrailingObjects<ExceptionType>());
   }
 
   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<ExtParameterInfo> getExtParameterInfos() const {
     assert(hasExtParameterInfos());
-    return ArrayRef<ExtParameterInfo>(getExtParameterInfosBuffer(),
+    return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(),
                                       getNumParams());
   }
 
@@ -3955,27 +4047,27 @@
   const ExtParameterInfo *getExtParameterInfosOrNull() const {
     if (!hasExtParameterInfos())
       return nullptr;
-    return getExtParameterInfosBuffer();
+    return getTrailingObjects<ExtParameterInfo>();
   }
 
   ExtParameterInfo getExtParameterInfo(unsigned I) const {
     assert(I < getNumParams() && "parameter index out of range");
     if (hasExtParameterInfos())
-      return getExtParameterInfosBuffer()[I];
+      return getTrailingObjects<ExtParameterInfo>()[I];
     return ExtParameterInfo();
   }
 
   ParameterABI getParameterABI(unsigned I) const {
     assert(I < getNumParams() && "parameter index out of range");
     if (hasExtParameterInfos())
-      return getExtParameterInfosBuffer()[I].getABI();
+      return getTrailingObjects<ExtParameterInfo>()[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<ExtParameterInfo>()[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<QualType> 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<FunctionTypeExtraBitfields>();
+    ExtraBits.NumExceptionType = epi.ExceptionSpec.Exceptions.size();
+  }
 
   // Fill in the trailing argument array.
-  auto *argSlot = reinterpret_cast<QualType *>(this+1);
-  for (unsigned i = 0; i != NumParams; ++i) {
+  auto *argSlot = getTrailingObjects<QualType>();
+  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<QualType *>(getTrailingObjects<ExceptionType>());
     unsigned I = 0;
     for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) {
       // Note that, before C++17, a dependent exception specification does
@@ -2878,33 +2884,36 @@
 
       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<Expr **>(argSlot + NumParams);
-    *noexSlot = epi.ExceptionSpec.NoexceptExpr;
+    *getTrailingObjects<Expr *>() = epi.ExceptionSpec.NoexceptExpr;
 
     if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() ||
         epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
       setInstantiationDependent();
 
     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<FunctionDecl **>(argSlot + NumParams);
+    auto **slot = getTrailingObjects<FunctionDecl *>();
     slot[0] = epi.ExceptionSpec.SourceDecl;
     slot[1] = epi.ExceptionSpec.SourceTemplate;
     // This exception specification doesn't make the type dependent, because
     // it's not instantiated as part of instantiating the type.
   } else if (getExceptionSpecType() == EST_Unevaluated) {
     // Store the function decl from which we will resolve our
     // exception specification.
-    auto **slot = reinterpret_cast<FunctionDecl **>(argSlot + NumParams);
+    auto **slot = getTrailingObjects<FunctionDecl *>();
     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<ExtParameterInfo *>(getExtParameterInfosBuffer());
-    for (unsigned i = 0; i != NumParams; ++i)
+    auto *extParamInfos = getTrailingObjects<ExtParameterInfo>();
+    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<PackExpansionType>())
         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 {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to