]> granicus.if.org Git - clang/commitdiff
Implement dependent alignment attribute support. This is a bit gross given the
authorChandler Carruth <chandlerc@gmail.com>
Fri, 25 Jun 2010 03:22:07 +0000 (03:22 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Fri, 25 Jun 2010 03:22:07 +0000 (03:22 +0000)
current attribute system, but it is enough to handle class templates which
specify parts of their alignment in terms of their template parameters.

This also replaces the attributes test in SemaTemplate with one that actually
tests working attributes instead of broken ones. I plan to add more tests here
for non-dependent attributes in a subsequent patch.

Thanks to John for walking me through some of this. =D

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106818 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Attr.h
lib/Sema/Sema.h
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/attributes.cpp

index 0f0215a7c8d6812cd4ec7cdd38369c14ae0289d4..9faa62eef6f76df4f6a7e0dc60075ab3acc16a56 100644 (file)
@@ -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;
index e719cd745377c375f0d57519e4bf9434991d7dba..9d5e290b2f66f87c26140f1e9ecdba291b5d0cdd 100644 (file)
@@ -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.
index 527b469fed8ff6265961b77eb6053201aa8fe14e..0f53fb92ef6458ee5927dbfa80bf30e8b87f1320 100644 (file)
@@ -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
index 1b28579e61d45f703582217047a4de2c8231268d..06f38e88d58d9c3cce572fec027c6543da476783 100644 (file)
@@ -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);
   }
 }
index b696c5cd98401ecdc4917e21cae407e668d876fc..f4c1887c25e2c4dc4f8cbb66690b9f7ad24ca633 100644 (file)
@@ -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;
+}