From: James Y Knight Date: Fri, 17 Jul 2015 18:21:37 +0000 (+0000) Subject: Fix alignment issues in Clang. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f9ae22bbac6c066418741e45afc8ea217aab952e;p=clang Fix alignment issues in Clang. Some const-correctness changes snuck in here too, since they were in the area of code I was modifying. This seems to make Clang actually work without Bus Error on 32bit-sparc. Follow-up patches will factor out a trailing-object helper class, to make classes using the idiom of appending objects to other objects easier to understand, and to ensure (with static_assert) that required alignment guarantees continue to hold. Differential Revision: http://reviews.llvm.org/D10272 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@242554 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 6b6ac3f7d5..43d8366f0d 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -70,8 +70,15 @@ namespace clang { /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. /// +/// Note: There are objects tacked on before the *beginning* of Decl +/// (and its subclasses) in its Decl::operator new(). Proper alignment +/// of all subclasses (not requiring more than DeclObjAlignment) is +/// asserted in DeclBase.cpp. class Decl { public: + /// \brief Alignment guaranteed when allocating Decl and any subtypes. + enum { DeclObjAlignment = llvm::AlignOf::Alignment }; + /// \brief Lists the kind of concrete classes of Decl. enum Kind { #define DECL(DERIVED, BASE) DERIVED, diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 0fc9b4947d..44b907f749 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -43,7 +43,7 @@ typedef llvm::PointerUnion3(T); /// }; /// \endcode -class DependentFunctionTemplateSpecializationInfo { - struct CA { - /// The number of potential template candidates. - unsigned NumTemplates; +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) + DependentFunctionTemplateSpecializationInfo { + /// The number of potential template candidates. + unsigned NumTemplates; - /// The number of template arguments. - unsigned NumArgs; - }; - - union { - // Force sizeof to be a multiple of sizeof(void*) so that the - // trailing data is aligned. - void *Aligner; - struct CA d; - }; + /// The number of template arguments. + unsigned NumArgs; /// The locations of the left and right angle brackets. SourceRange AngleLocs; FunctionTemplateDecl * const *getTemplates() const { - return reinterpret_cast(this+1); + return reinterpret_cast( + &getTemplateArgs()[NumArgs]); } public: @@ -572,9 +565,7 @@ public: /// \brief Returns the number of function templates that this might /// be a specialization of. - unsigned getNumTemplates() const { - return d.NumTemplates; - } + unsigned getNumTemplates() const { return NumTemplates; } /// \brief Returns the i'th template candidate. FunctionTemplateDecl *getTemplate(unsigned I) const { @@ -584,14 +575,11 @@ public: /// \brief Returns the explicit template arguments that were given. const TemplateArgumentLoc *getTemplateArgs() const { - return reinterpret_cast( - &getTemplates()[getNumTemplates()]); + return reinterpret_cast(this + 1); } /// \brief Returns the number of explicit template arguments that were given. - unsigned getNumTemplateArgs() const { - return d.NumArgs; - } + unsigned getNumTemplateArgs() const { return NumArgs; } /// \brief Returns the nth template argument. const TemplateArgumentLoc &getTemplateArg(unsigned I) const { diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h index ad5287314d..aad7726f84 100644 --- a/include/clang/AST/EvaluatedExprVisitor.h +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -88,8 +88,8 @@ public: void VisitLambdaExpr(PTR(LambdaExpr) LE) { // Only visit the capture initializers, and not the body. - for (LambdaExpr::capture_init_iterator I = LE->capture_init_begin(), - E = LE->capture_init_end(); + for (LambdaExpr::const_capture_init_iterator I = LE->capture_init_begin(), + E = LE->capture_init_end(); I != E; ++I) if (*I) this->Visit(*I); diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 0d1cf3a32e..24d09fb9af 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -897,7 +897,7 @@ public: /// DeclRefExprBits.RefersToEnclosingVariableOrCapture /// Specifies when this declaration reference expression (validly) /// refers to an enclosed local or a captured variable. -class DeclRefExpr : public Expr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DeclRefExpr : public Expr { /// \brief The declaration that we are referencing. ValueDecl *D; @@ -1051,13 +1051,17 @@ public: if (!hasTemplateKWAndArgsInfo()) return nullptr; - if (hasFoundDecl()) + if (hasFoundDecl()) { return reinterpret_cast( - &getInternalFoundDecl() + 1); + llvm::alignAddr(&getInternalFoundDecl() + 1, + llvm::alignOf())); + } - if (hasQualifier()) + if (hasQualifier()) { return reinterpret_cast( - &getInternalQualifierLoc() + 1); + llvm::alignAddr(&getInternalQualifierLoc() + 1, + llvm::alignOf())); + } return reinterpret_cast(this + 1); } @@ -2301,9 +2305,9 @@ public: /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// -class MemberExpr : public Expr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) MemberExpr : public Expr { /// Extra data stored in some member expressions. - struct MemberNameQualifier { + struct LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) MemberNameQualifier { /// \brief The nested-name-specifier that qualifies the name, including /// source-location information. NestedNameSpecifierLoc QualifierLoc; diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 1dbf5743c1..cc185303ed 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1401,25 +1401,39 @@ class LambdaExpr : public Expr { ExplicitResultType(false), HasArrayIndexVars(true) { getStoredStmts()[NumCaptures] = nullptr; } - - Stmt **getStoredStmts() const { - return reinterpret_cast(const_cast(this) + 1); + + Stmt **getStoredStmts() { return reinterpret_cast(this + 1); } + + Stmt *const *getStoredStmts() const { + return reinterpret_cast(this + 1); } - + /// \brief Retrieve the mapping from captures to the first array index /// variable. - unsigned *getArrayIndexStarts() const { + unsigned *getArrayIndexStarts() { return reinterpret_cast(getStoredStmts() + NumCaptures + 1); } + const unsigned *getArrayIndexStarts() const { + return reinterpret_cast(getStoredStmts() + NumCaptures + + 1); + } + /// \brief Retrieve the complete set of array-index variables. - VarDecl **getArrayIndexVars() const { + VarDecl **getArrayIndexVars() { unsigned ArrayIndexSize = llvm::RoundUpToAlignment( sizeof(unsigned) * (NumCaptures + 1), llvm::alignOf()); return reinterpret_cast( reinterpret_cast(getArrayIndexStarts()) + ArrayIndexSize); } + VarDecl *const *getArrayIndexVars() const { + unsigned ArrayIndexSize = llvm::RoundUpToAlignment( + sizeof(unsigned) * (NumCaptures + 1), llvm::alignOf()); + return reinterpret_cast( + reinterpret_cast(getArrayIndexStarts()) + ArrayIndexSize); + } + public: /// \brief Construct a new lambda expression. static LambdaExpr *Create(const ASTContext &C, @@ -1501,31 +1515,54 @@ public: /// arguments. typedef Expr **capture_init_iterator; + /// \brief Const iterator that walks over the capture initialization + /// arguments. + typedef Expr *const *const_capture_init_iterator; + /// \brief Retrieve the initialization expressions for this lambda's captures. - llvm::iterator_range capture_inits() const { + llvm::iterator_range capture_inits() { return llvm::iterator_range(capture_init_begin(), capture_init_end()); } + /// \brief Retrieve the initialization expressions for this lambda's captures. + llvm::iterator_range capture_inits() const { + return llvm::iterator_range( + capture_init_begin(), capture_init_end()); + } + /// \brief Retrieve the first initialization argument for this /// lambda expression (which initializes the first capture field). - capture_init_iterator capture_init_begin() const { + capture_init_iterator capture_init_begin() { return reinterpret_cast(getStoredStmts()); } + /// \brief Retrieve the first initialization argument for this + /// lambda expression (which initializes the first capture field). + const_capture_init_iterator capture_init_begin() const { + return reinterpret_cast(getStoredStmts()); + } + /// \brief Retrieve the iterator pointing one past the last /// initialization argument for this lambda expression. - capture_init_iterator capture_init_end() const { - return capture_init_begin() + NumCaptures; + capture_init_iterator capture_init_end() { + return capture_init_begin() + NumCaptures; } - /// \brief Retrieve the set of index variables used in the capture + /// \brief Retrieve the iterator pointing one past the last + /// initialization argument for this lambda expression. + const_capture_init_iterator capture_init_end() const { + return capture_init_begin() + NumCaptures; + } + + /// \brief Retrieve the set of index variables used in the capture /// initializer of an array captured by copy. /// - /// \param Iter The iterator that points at the capture initializer for + /// \param Iter The iterator that points at the capture initializer for /// which we are extracting the corresponding index variables. - ArrayRef getCaptureInitIndexVars(capture_init_iterator Iter) const; - + ArrayRef + getCaptureInitIndexVars(const_capture_init_iterator Iter) const; + /// \brief Retrieve the source range covering the lambda introducer, /// which contains the explicit capture list surrounded by square /// brackets ([...]). @@ -2302,7 +2339,7 @@ public: /// \brief A reference to an overloaded function set, either an /// \c UnresolvedLookupExpr or an \c UnresolvedMemberExpr. -class OverloadExpr : public Expr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) OverloadExpr : public Expr { /// \brief The common name of these declarations. DeclarationNameInfo NameInfo; @@ -2606,7 +2643,8 @@ public: /// qualifier (X::) and the name of the entity being referenced /// ("value"). Such expressions will instantiate to a DeclRefExpr once the /// declaration can be found. -class DependentScopeDeclRefExpr : public Expr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentScopeDeclRefExpr + : public Expr { /// \brief The nested-name-specifier that qualifies this unresolved /// declaration name. NestedNameSpecifierLoc QualifierLoc; @@ -2951,7 +2989,8 @@ public: /// Like UnresolvedMemberExprs, these can be either implicit or /// explicit accesses. It is only possible to get one of these with /// an implicit access if a qualifier is provided. -class CXXDependentScopeMemberExpr : public Expr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) CXXDependentScopeMemberExpr + : public Expr { /// \brief The expression for the base pointer or class reference, /// e.g., the \c x in x.f. Can be null in implicit accesses. Stmt *Base; @@ -3206,7 +3245,8 @@ public: /// In the final AST, an explicit access always becomes a MemberExpr. /// An implicit access may become either a MemberExpr or a /// DeclRefExpr, depending on whether the member is static. -class UnresolvedMemberExpr : public OverloadExpr { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) UnresolvedMemberExpr + : public OverloadExpr { /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; @@ -3330,6 +3370,17 @@ public: } }; +inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) + return nullptr; + if (isa(this)) + return reinterpret_cast( + cast(this) + 1); + else + return reinterpret_cast( + cast(this) + 1); +} + /// \brief Represents a C++11 noexcept expression (C++ [expr.unary.noexcept]). /// /// The noexcept expression tests whether a given expression might throw. Its @@ -3451,15 +3502,6 @@ public: } }; -inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() { - if (!HasTemplateKWAndArgsInfo) return nullptr; - if (isa(this)) - return reinterpret_cast - (cast(this) + 1); - else - return reinterpret_cast - (cast(this) + 1); -} /// \brief Represents an expression that computes the length of a parameter /// pack. diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index f28e5196c7..a7e82f9d93 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -341,6 +341,8 @@ public: child_range children() { // Note: we're taking advantage of the layout of the KeyValuePair struct // here. If that struct changes, this code will need to change as well. + static_assert(sizeof(KeyValuePair) == sizeof(Stmt *) * 2, + "KeyValuePair is expected size"); return child_range(reinterpret_cast(this + 1), reinterpret_cast(this + 1) + NumElements * 2); } diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index ce9449dc46..5104235706 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -2076,8 +2076,10 @@ private: /// \brief Construct an empty captured statement. CapturedStmt(EmptyShell Empty, unsigned NumCaptures); - Stmt **getStoredStmts() const { - return reinterpret_cast(const_cast(this) + 1); + Stmt **getStoredStmts() { return reinterpret_cast(this + 1); } + + Stmt *const *getStoredStmts() const { + return reinterpret_cast(this + 1); } Capture *getStoredCaptures() const; @@ -2096,14 +2098,12 @@ public: /// \brief Retrieve the statement being captured. Stmt *getCapturedStmt() { return getStoredStmts()[NumCaptures]; } - const Stmt *getCapturedStmt() const { - return const_cast(this)->getCapturedStmt(); - } + const Stmt *getCapturedStmt() const { return getStoredStmts()[NumCaptures]; } /// \brief Retrieve the outlined function declaration. CapturedDecl *getCapturedDecl() { return CapDeclAndKind.getPointer(); } const CapturedDecl *getCapturedDecl() const { - return const_cast(this)->getCapturedDecl(); + return CapDeclAndKind.getPointer(); } /// \brief Set the outlined function declaration. @@ -2164,18 +2164,36 @@ public: typedef Expr **capture_init_iterator; typedef llvm::iterator_range capture_init_range; - capture_init_range capture_inits() const { + /// \brief Const iterator that walks over the capture initialization + /// arguments. + typedef Expr *const *const_capture_init_iterator; + typedef llvm::iterator_range + const_capture_init_range; + + capture_init_range capture_inits() { return capture_init_range(capture_init_begin(), capture_init_end()); } + const_capture_init_range capture_inits() const { + return const_capture_init_range(capture_init_begin(), capture_init_end()); + } + /// \brief Retrieve the first initialization argument. - capture_init_iterator capture_init_begin() const { + capture_init_iterator capture_init_begin() { return reinterpret_cast(getStoredStmts()); } + const_capture_init_iterator capture_init_begin() const { + return reinterpret_cast(getStoredStmts()); + } + /// \brief Retrieve the iterator pointing one past the last initialization /// argument. - capture_init_iterator capture_init_end() const { + capture_init_iterator capture_init_end() { + return capture_init_begin() + NumCaptures; + } + + const_capture_init_iterator capture_init_end() const { return capture_init_begin() + NumCaptures; } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index cf70005ac8..e1ebd72795 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -3118,11 +3118,13 @@ private: assert(hasAnyConsumedParams()); // Find the end of the exceptions. - Expr *const *eh_end = reinterpret_cast(param_type_end()); - if (getExceptionSpecType() != EST_ComputedNoexcept) - eh_end += NumExceptions; - else + Expr *const *eh_end = reinterpret_cast(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); return reinterpret_cast(eh_end); } @@ -3295,7 +3297,6 @@ public: const ExtProtoInfo &EPI, const ASTContext &Context); }; - /// \brief Represents the dependent type named by a dependently-scoped /// typename using declaration, e.g. /// using typename Base::foo; @@ -3936,8 +3937,9 @@ public: /// TemplateArguments, followed by a QualType representing the /// non-canonical aliased type when the template is a type alias /// template. -class TemplateSpecializationType - : public Type, public llvm::FoldingSetNode { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) TemplateSpecializationType + : public Type, + public llvm::FoldingSetNode { /// The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a @@ -4328,8 +4330,9 @@ public: /// Represents a template specialization type whose template cannot be /// resolved, e.g. /// A::template B -class DependentTemplateSpecializationType : - public TypeWithKeyword, public llvm::FoldingSetNode { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) DependentTemplateSpecializationType + : public TypeWithKeyword, + public llvm::FoldingSetNode { /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index f4d20b8d52..df68845d7c 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -206,6 +206,7 @@ private: /// \brief Return the TypeLoc for a type source info. inline TypeLoc TypeSourceInfo::getTypeLoc() const { + // TODO: is this alignment already sufficient? return TypeLoc(Ty, const_cast(static_cast(this + 1))); } diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 4d18633cd3..2fedc79401 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -137,11 +137,9 @@ private: AttributeList *NextInPool; /// Arguments, if any, are stored immediately following the object. - ArgsUnion *getArgsBuffer() { - return reinterpret_cast(this+1); - } + ArgsUnion *getArgsBuffer() { return reinterpret_cast(this + 1); } ArgsUnion const *getArgsBuffer() const { - return reinterpret_cast(this+1); + return reinterpret_cast(this + 1); } enum AvailabilitySlot { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ea4b2f517c..946d1bae21 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3116,8 +3116,8 @@ FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, const TemplateArgumentListInfo &TemplateArgs) { assert(TemplateOrSpecialization.isNull()); size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); - Size += Templates.size() * sizeof(FunctionTemplateDecl*); Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc); + Size += Templates.size() * sizeof(FunctionTemplateDecl *); void *Buffer = Context.Allocate(Size); DependentFunctionTemplateSpecializationInfo *Info = new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, @@ -3132,8 +3132,8 @@ DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, static_assert(sizeof(*this) % llvm::AlignOf::Alignment == 0, "Trailing data is unaligned!"); - d.NumTemplates = Ts.size(); - d.NumArgs = TArgs.size(); + NumTemplates = Ts.size(); + NumArgs = TArgs.size(); FunctionTemplateDecl **TsArray = const_cast(getTemplates()); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 4fcec53d6e..e772f19533 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -45,10 +45,19 @@ void Decl::updateOutOfDate(IdentifierInfo &II) const { getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); } +#define DECL(DERIVED, BASE) \ + static_assert(Decl::DeclObjAlignment >= \ + llvm::AlignOf::Alignment, \ + "Alignment sufficient after objects prepended to " #DERIVED); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + void *Decl::operator new(std::size_t Size, const ASTContext &Context, unsigned ID, std::size_t Extra) { // Allocate an extra 8 bytes worth of storage, which ensures that the - // resulting pointer will still be 8-byte aligned. + // resulting pointer will still be 8-byte aligned. + static_assert(sizeof(unsigned) * 2 >= DeclObjAlignment, + "Decl won't be misaligned"); void *Start = Context.Allocate(Size + Extra + 8); void *Result = (char*)Start + 8; @@ -69,7 +78,13 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx, // With local visibility enabled, we track the owning module even for local // declarations. if (Ctx.getLangOpts().ModulesLocalVisibility) { - void *Buffer = ::operator new(sizeof(Module *) + Size + Extra, Ctx); + // Ensure required alignment of the resulting object by adding extra + // padding at the start if required. + size_t ExtraAlign = + llvm::OffsetToAlignment(sizeof(Module *), DeclObjAlignment); + char *Buffer = reinterpret_cast( + ::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx)); + Buffer += ExtraAlign; return new (Buffer) Module*(nullptr) + 1; } return ::operator new(Size + Extra, Ctx); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2e066b2c42..6c048f96d4 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -399,10 +399,15 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, Size += sizeof(NestedNameSpecifierLoc); if (FoundD) Size += sizeof(NamedDecl *); - if (TemplateArgs) + if (TemplateArgs) { + Size = llvm::RoundUpToAlignment(Size, + llvm::alignOf()); Size += ASTTemplateKWAndArgsInfo::sizeFor(TemplateArgs->size()); - else if (TemplateKWLoc.isValid()) + } else if (TemplateKWLoc.isValid()) { + Size = llvm::RoundUpToAlignment(Size, + llvm::alignOf()); Size += ASTTemplateKWAndArgsInfo::sizeFor(0); + } void *Mem = Context.Allocate(Size, llvm::alignOf()); return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D, @@ -420,8 +425,11 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, Size += sizeof(NestedNameSpecifierLoc); if (HasFoundDecl) Size += sizeof(NamedDecl *); - if (HasTemplateKWAndArgsInfo) + if (HasTemplateKWAndArgsInfo) { + Size = llvm::RoundUpToAlignment(Size, + llvm::alignOf()); Size += ASTTemplateKWAndArgsInfo::sizeFor(NumTemplateArgs); + } void *Mem = Context.Allocate(Size, llvm::alignOf()); return new (Mem) DeclRefExpr(EmptyShell()); @@ -3939,7 +3947,8 @@ DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators, SourceLocation ColonOrEqualLoc, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + - sizeof(Stmt *) * (IndexExprs.size() + 1), 8); + sizeof(Stmt *) * (IndexExprs.size() + 1), + llvm::alignOf()); return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators, ColonOrEqualLoc, UsesColonSyntax, IndexExprs, Init); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index d6f2ce63a0..2a93f71429 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -1070,15 +1070,15 @@ LambdaExpr::capture_range LambdaExpr::implicit_captures() const { return capture_range(implicit_capture_begin(), implicit_capture_end()); } -ArrayRef -LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const { +ArrayRef +LambdaExpr::getCaptureInitIndexVars(const_capture_init_iterator Iter) const { assert(HasArrayIndexVars && "No array index-var data?"); unsigned Index = Iter - capture_init_begin(); assert(Index < getLambdaClass()->getLambdaData().NumCaptures && "Capture index out-of-range"); - VarDecl **IndexVars = getArrayIndexVars(); - unsigned *IndexStarts = getArrayIndexStarts(); + VarDecl *const *IndexVars = getArrayIndexVars(); + const unsigned *IndexStarts = getArrayIndexStarts(); return llvm::makeArrayRef(IndexVars + IndexStarts[Index], IndexVars + IndexStarts[Index + 1]); } @@ -1099,9 +1099,13 @@ TemplateParameterList *LambdaExpr::getTemplateParameterList() const { } CompoundStmt *LambdaExpr::getBody() const { + // FIXME: this mutation in getBody is bogus. It should be + // initialized in ASTStmtReader::VisitLambdaExpr, but for reasons I + // don't understand, that doesn't work. if (!getStoredStmts()[NumCaptures]) - getStoredStmts()[NumCaptures] = getCallOperator()->getBody(); - + *const_cast(&getStoredStmts()[NumCaptures]) = + getCallOperator()->getBody(); + return reinterpret_cast(getStoredStmts()[NumCaptures]); } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index c0aab4c4db..80b6be88a3 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -822,7 +822,7 @@ SourceLocation ObjCAtTryStmt::getLocEnd() const { CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc, Stmt *tryBlock, ArrayRef handlers) { std::size_t Size = sizeof(CXXTryStmt); - Size += ((handlers.size() + 1) * sizeof(Stmt)); + Size += ((handlers.size() + 1) * sizeof(Stmt *)); void *Mem = C.Allocate(Size, llvm::alignOf()); return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers); @@ -831,7 +831,7 @@ CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc, CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty, unsigned numHandlers) { std::size_t Size = sizeof(CXXTryStmt); - Size += ((numHandlers + 1) * sizeof(Stmt)); + Size += ((numHandlers + 1) * sizeof(Stmt *)); void *Mem = C.Allocate(Size, llvm::alignOf()); return new (Mem) CXXTryStmt(Empty, numHandlers); @@ -2250,4 +2250,3 @@ OMPTeamsDirective *OMPTeamsDirective::CreateEmpty(const ASTContext &C, C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); return new (Mem) OMPTeamsDirective(NumClauses); } - diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index d97e40554e..3d4c4850f6 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -96,6 +96,7 @@ RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { /// Push an entry of the given size onto this protected-scope stack. char *EHScopeStack::allocate(size_t Size) { + Size = llvm::RoundUpToAlignment(Size, ScopeStackAlignment); if (!StartOfBuffer) { unsigned Capacity = 1024; while (Capacity < Size) Capacity *= 2; @@ -125,6 +126,10 @@ char *EHScopeStack::allocate(size_t Size) { return StartOfData; } +void EHScopeStack::deallocate(size_t Size) { + StartOfData += llvm::RoundUpToAlignment(Size, ScopeStackAlignment); +} + bool EHScopeStack::containsOnlyLifetimeMarkers( EHScopeStack::stable_iterator Old) const { for (EHScopeStack::iterator it = begin(); stabilize(it) != Old; it++) { @@ -166,7 +171,6 @@ EHScopeStack::stable_iterator EHScopeStack::getInnermostActiveEHScope() const { void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { - assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); bool IsNormalCleanup = Kind & NormalCleanup; bool IsEHCleanup = Kind & EHCleanup; @@ -194,7 +198,7 @@ void EHScopeStack::popCleanup() { EHCleanupScope &Cleanup = cast(*begin()); InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); InnermostEHScope = Cleanup.getEnclosingEHScope(); - StartOfData += Cleanup.getAllocatedSize(); + deallocate(Cleanup.getAllocatedSize()); // Destroy the cleanup. Cleanup.Destroy(); @@ -224,7 +228,7 @@ void EHScopeStack::popFilter() { assert(!empty() && "popping exception stack when not empty"); EHFilterScope &filter = cast(*begin()); - StartOfData += EHFilterScope::getSizeForNumFilters(filter.getNumFilters()); + deallocate(EHFilterScope::getSizeForNumFilters(filter.getNumFilters())); InnermostEHScope = filter.getEnclosingEHScope(); } diff --git a/lib/CodeGen/CGCleanup.h b/lib/CodeGen/CGCleanup.h index 81c64123df..34866d4c47 100644 --- a/lib/CodeGen/CGCleanup.h +++ b/lib/CodeGen/CGCleanup.h @@ -216,7 +216,7 @@ public: }; /// A cleanup scope which generates the cleanup blocks lazily. -class EHCleanupScope : public EHScope { +class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) EHCleanupScope : public EHScope { /// The nearest normal cleanup scope enclosing this one. EHScopeStack::stable_iterator EnclosingNormal; @@ -396,6 +396,15 @@ public: return (Scope->getKind() == Cleanup); } }; +// NOTE: there's a bunch of different data classes tacked on after an +// EHCleanupScope. It is asserted (in EHScopeStack::pushCleanup*) that +// they don't require greater alignment than ScopeStackAlignment. So, +// EHCleanupScope ought to have alignment equal to that -- not more +// (would be misaligned by the stack allocator), and not less (would +// break the appended classes). +static_assert(llvm::AlignOf::Alignment == + EHScopeStack::ScopeStackAlignment, + "EHCleanupScope expected alignment"); /// An exceptions scope which filters exceptions thrown through it. /// Only exceptions matching the filter types will be permitted to be @@ -472,27 +481,27 @@ public: EHScope &operator*() const { return *get(); } iterator &operator++() { + size_t Size; switch (get()->getKind()) { case EHScope::Catch: - Ptr += EHCatchScope::getSizeForNumHandlers( - static_cast(get())->getNumHandlers()); + Size = EHCatchScope::getSizeForNumHandlers( + static_cast(get())->getNumHandlers()); break; case EHScope::Filter: - Ptr += EHFilterScope::getSizeForNumFilters( - static_cast(get())->getNumFilters()); + Size = EHFilterScope::getSizeForNumFilters( + static_cast(get())->getNumFilters()); break; case EHScope::Cleanup: - Ptr += static_cast(get()) - ->getAllocatedSize(); + Size = static_cast(get())->getAllocatedSize(); break; case EHScope::Terminate: - Ptr += EHTerminateScope::getSize(); + Size = EHTerminateScope::getSize(); break; } - + Ptr += llvm::RoundUpToAlignment(Size, ScopeStackAlignment); return *this; } @@ -528,7 +537,7 @@ inline void EHScopeStack::popCatch() { EHCatchScope &scope = cast(*begin()); InnermostEHScope = scope.getEnclosingEHScope(); - StartOfData += EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers()); + deallocate(EHCatchScope::getSizeForNumHandlers(scope.getNumHandlers())); } inline void EHScopeStack::popTerminate() { @@ -536,7 +545,7 @@ inline void EHScopeStack::popTerminate() { EHTerminateScope &scope = cast(*begin()); InnermostEHScope = scope.getEnclosingEHScope(); - StartOfData += EHTerminateScope::getSize(); + deallocate(EHTerminateScope::getSize()); } inline EHScopeStack::iterator EHScopeStack::find(stable_iterator sp) const { diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index c7adccaeea..371f44fcc9 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1844,8 +1844,8 @@ void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) { MakeAddrLValue(Slot.getAddr(), E->getType(), Slot.getAlignment()); CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); - for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(), - e = E->capture_init_end(); + for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(), + e = E->capture_init_end(); i != e; ++i, ++CurField) { // Emit initialization LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 7a0b8a35be..f58c2f440a 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -2156,8 +2156,8 @@ LValue CodeGenFunction::InitCapturedStruct(const CapturedStmt &S) { CreateMemTemp(RecordTy, "agg.captured"), RecordTy); RecordDecl::field_iterator CurField = RD->field_begin(); - for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(), - E = S.capture_init_end(); + for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(), + E = S.capture_init_end(); I != E; ++I, ++CurField) { LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField); if (CurField->hasCapturedVLAType()) { diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h index a7951888c8..7b541b53ea 100644 --- a/lib/CodeGen/EHScopeStack.h +++ b/lib/CodeGen/EHScopeStack.h @@ -96,6 +96,8 @@ enum CleanupKind : unsigned { /// and catch blocks. class EHScopeStack { public: + enum { ScopeStackAlignment = llvm::AlignOf::Alignment }; + /// A saved depth on the scope stack. This is necessary because /// pushing scopes onto the stack invalidates iterators. class stable_iterator { @@ -248,6 +250,7 @@ private: SmallVector BranchFixups; char *allocate(size_t Size); + void deallocate(size_t Size); void *pushCleanup(CleanupKind K, size_t DataSize); @@ -259,6 +262,8 @@ public: /// Push a lazily-created cleanup on the stack. template void pushCleanup(CleanupKind Kind, As... A) { + static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, + "Cleanup's alignment is too large."); void *Buffer = pushCleanup(Kind, sizeof(T)); Cleanup *Obj = new (Buffer) T(A...); (void) Obj; @@ -267,6 +272,8 @@ public: /// Push a lazily-created cleanup on the stack. Tuple version. template void pushCleanupTuple(CleanupKind Kind, std::tuple A) { + static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, + "Cleanup's alignment is too large."); void *Buffer = pushCleanup(Kind, sizeof(T)); Cleanup *Obj = new (Buffer) T(std::move(A)); (void) Obj; @@ -287,6 +294,8 @@ public: /// stack is modified. template T *pushCleanupWithExtra(CleanupKind Kind, size_t N, As... A) { + static_assert(llvm::AlignOf::Alignment <= ScopeStackAlignment, + "Cleanup's alignment is too large."); void *Buffer = pushCleanup(Kind, sizeof(T) + T::getExtraSize(N)); return new (Buffer) T(N, A...); } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 094187025d..8a9372336e 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -973,8 +973,9 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::LambdaExprClass: { const LambdaExpr *Lambda = cast(E); CanThrowResult CT = CT_Cannot; - for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(), - CapEnd = Lambda->capture_init_end(); + for (LambdaExpr::const_capture_init_iterator + Cap = Lambda->capture_init_begin(), + CapEnd = Lambda->capture_init_end(); Cap != CapEnd; ++Cap) CT = mergeCanThrow(CT, canThrow(*Cap)); return CT;