diff options
-rw-r--r-- | include/clang/AST/Attr.h | 35 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 23 | ||||
-rw-r--r-- | test/SemaTemplate/attributes.cpp | 23 |
5 files changed, 87 insertions, 27 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 0f0215a7c8..9faa62eef6 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -26,6 +26,7 @@ namespace clang { class ASTContext; class IdentifierInfo; class ObjCInterfaceDecl; + class Expr; } // Defined in ASTContext.h @@ -147,22 +148,44 @@ public: DEF_SIMPLE_ATTR(AlignMac68k); +/// \brief Atribute for specifying the alignment of a variable or type. +/// +/// This node will either contain the precise Alignment (in bits, not bytes!) +/// or will contain the expression for the alignment attribute in the case of +/// a dependent expression within a class or function template. At template +/// instantiation time these are transformed into concrete attributes. class AlignedAttr : public Attr { unsigned Alignment; + Expr *AlignmentExpr; public: AlignedAttr(unsigned alignment) - : Attr(attr::Aligned), Alignment(alignment) {} + : Attr(attr::Aligned), Alignment(alignment), AlignmentExpr(0) {} + AlignedAttr(Expr *E) + : Attr(attr::Aligned), Alignment(0), AlignmentExpr(E) {} + + /// getAlignmentExpr - Get a dependent alignment expression if one is present. + Expr *getAlignmentExpr() const { + return AlignmentExpr; + } + + /// isDependent - Is the alignment a dependent expression + bool isDependent() const { + return getAlignmentExpr(); + } + + /// getAlignment - The specified alignment in bits. Requires !isDependent(). + unsigned getAlignment() const { + assert(!isDependent() && "Cannot get a value dependent alignment"); + return Alignment; + } - /// getAlignment - The specified alignment in bits. - unsigned getAlignment() const { return Alignment; } - /// getMaxAlignment - Get the maximum alignment of attributes on this list. unsigned getMaxAlignment() const { const AlignedAttr *Next = getNext<AlignedAttr>(); if (Next) - return std::max(Next->getMaxAlignment(), Alignment); + return std::max(Next->getMaxAlignment(), getAlignment()); else - return Alignment; + return getAlignment(); } virtual Attr* clone(ASTContext &C) const; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e719cd7453..9d5e290b2f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -4088,6 +4088,9 @@ public: /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. + void AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E); + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 527b469fed..0f53fb92ef 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1458,7 +1458,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) AnnotateAttr(S.Context, SE->getString())); } -static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; @@ -1469,30 +1469,36 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // than GNU's, and should error out when it is used to specify a // weaker alignment, rather than being silently ignored. - unsigned Align = 0; if (Attr.getNumArgs() == 0) { // FIXME: This should be the target specific maximum alignment. // (For now we just use 128 bits which is the maximum on X86). - Align = 128; - d->addAttr(::new (S.Context) AlignedAttr(Align)); + D->addAttr(::new (S.Context) AlignedAttr(128)); + return; + } + + S.AddAlignedAttr(Attr.getLoc(), D, static_cast<Expr *>(Attr.getArg(0))); +} + +void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { + if (E->isTypeDependent() || E->isValueDependent()) { + // Save dependent expressions in the AST to be instantiated. + D->addAttr(::new (Context) AlignedAttr(E)); return; } - Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0)); llvm::APSInt Alignment(32); - if (alignmentExpr->isTypeDependent() || alignmentExpr->isValueDependent() || - !alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) - << "aligned" << alignmentExpr->getSourceRange(); + if (!E->isIntegerConstantExpr(Alignment, Context)) { + Diag(AttrLoc, diag::err_attribute_argument_not_int) + << "aligned" << E->getSourceRange(); return; } if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) { - S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two) - << alignmentExpr->getSourceRange(); + Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two) + << E->getSourceRange(); return; } - d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8)); + D->addAttr(::new (Context) AlignedAttr(Alignment.getZExtValue() * 8)); } /// HandleModeAttr - This attribute modifies the width of a decl with primitive diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1b28579e61..06f38e88d5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -143,14 +143,29 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, return false; } -// FIXME: Is this too simple? +// FIXME: Is this still too simple? void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) { - for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; + for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; TmplAttr = TmplAttr->getNext()) { - + // FIXME: This should be generalized to more than just the AlignedAttr. + if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) { + if (Aligned->isDependent()) { + // The alignment expression is not potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(SemaRef, + Action::Unevaluated); + + OwningExprResult Result = SemaRef.SubstExpr(Aligned->getAlignmentExpr(), + TemplateArgs); + if (!Result.isInvalid()) + // FIXME: Is this the correct source location? + SemaRef.AddAlignedAttr(Aligned->getAlignmentExpr()->getExprLoc(), + New, Result.takeAs<Expr>()); + continue; + } + } + // FIXME: Is cloning correct for all attributes? Attr *NewAttr = TmplAttr->clone(SemaRef.Context); - New->addAttr(NewAttr); } } diff --git a/test/SemaTemplate/attributes.cpp b/test/SemaTemplate/attributes.cpp index b696c5cd98..f4c1887c25 100644 --- a/test/SemaTemplate/attributes.cpp +++ b/test/SemaTemplate/attributes.cpp @@ -1,8 +1,21 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template<int N> -struct X { - struct __attribute__((__aligned__((N)))) Aligned { }; // expected-error{{'aligned' attribute requires integer constant}} +namespace attribute_aligned { + template<int N> + struct X { + char c[1] __attribute__((__aligned__((N)))); // expected-error {{alignment is not a power of 2}} + }; - int __attribute__((__address_space__(N))) *ptr; // expected-error{{attribute requires 1 argument(s)}} -}; + template <bool X> struct check { + int check_failed[X ? 1 : -1]; // expected-error {{array size is negative}} + }; + + template <int N> struct check_alignment { + typedef check<N == sizeof(X<N>)> t; // expected-note {{in instantiation}} + }; + + check_alignment<1>::t c1; + check_alignment<2>::t c2; + check_alignment<3>::t c3; // expected-note 2 {{in instantiation}} + check_alignment<4>::t c4; +} |