r174157 - Implement [dcl.align]p5 and C11 6.7.5/4: alignas cannot underalign.

Richard Smith richard-llvm at metafoo.co.uk
Fri Feb 1 00:12:08 PST 2013


Author: rsmith
Date: Fri Feb  1 02:12:08 2013
New Revision: 174157

URL: http://llvm.org/viewvc/llvm-project?rev=174157&view=rev
Log:
Implement [dcl.align]p5 and C11 6.7.5/4: alignas cannot underalign.
Also support alignas(0), which C++11 and C11 require us to ignore.

Added:
    cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/Sema/alignas.c
    cfe/trunk/test/SemaCXX/attr-cxx0x.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Feb  1 02:12:08 2013
@@ -161,8 +161,9 @@ def Aligned : InheritableAttr {
   let Subjects = [NonBitField, NormalVar, Tag];
   let Args = [AlignedArgument<"Alignment">];
   let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
-                   Accessor<"isAlignas",
-                   [Keyword<"alignas">, Keyword<"_Alignas">]>,
+                   Accessor<"isC11", [Keyword<"_Alignas">]>,
+                   Accessor<"isAlignas", [Keyword<"alignas">,
+                                          Keyword<"_Alignas">]>,
                    Accessor<"isDeclspec",[Declspec<"align">]>];
 }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb  1 02:12:08 2013
@@ -1657,6 +1657,8 @@ def err_alignas_attribute_wrong_decl_typ
   "%0 attribute cannot be applied to a %select{"
   "function parameter|variable with 'register' storage class|"
   "'catch' variable|bit-field}1">;
+def err_alignas_underaligned : Error<
+  "requested alignment is less than minimum alignment of %1 for type %0">;
 def err_attribute_first_argument_not_int_or_bool : Error<
   "%0 attribute first argument must be of int or bool type">;
 def err_attribute_argument_outof_range : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb  1 02:12:08 2013
@@ -2351,6 +2351,7 @@ public:
   bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, 
                             const FunctionDecl *FD = 0);
   bool CheckNoReturnAttr(const AttributeList &attr);
+  void CheckAlignasUnderalignment(Decl *D);
 
   /// \brief Stmt attributes - this routine is the top level dispatcher.
   StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Feb  1 02:12:08 2013
@@ -4611,6 +4611,9 @@ Sema::ActOnVariableDeclarator(Scope *S, 
   // Handle attributes prior to checking for duplicates in MergeVarDecl
   ProcessDeclAttributes(S, NewVD, D);
 
+  if (NewVD->hasAttrs())
+    CheckAlignasUnderalignment(NewVD);
+
   if (getLangOpts().CUDA) {
     // CUDA B.2.5: "__shared__ and __constant__ variables have implied static
     // storage [duration]."
@@ -10158,10 +10161,14 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
 
   // FIXME: We need to pass in the attributes given an AST
   // representation, not a parser representation.
-  if (D)
+  if (D) {
     // FIXME: What to pass instead of TUScope?
     ProcessDeclAttributes(TUScope, NewFD, *D);
 
+    if (NewFD->hasAttrs())
+      CheckAlignasUnderalignment(NewFD);
+  }
+
   // In auto-retain/release, infer strong retension for fields of
   // retainable type.
   if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
@@ -10680,6 +10687,8 @@ void Sema::ActOnFields(Scope* S,
     if (!Completed)
       Record->completeDefinition();
 
+    if (Record->hasAttrs())
+      CheckAlignasUnderalignment(Record);
   } else {
     ObjCIvarDecl **ClsFields =
       reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -11427,6 +11436,10 @@ void Sema::ActOnEnumBody(SourceLocation 
     DeclsInPrototypeScope.push_back(Enum);
 
   CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
+
+  // Now that the enum type is defined, ensure it's not been underaligned.
+  if (Enum->hasAttrs())
+    CheckAlignasUnderalignment(Enum);
 }
 
 Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Feb  1 02:12:08 2013
@@ -3272,10 +3272,32 @@ static void handleAlignedAttr(Sema &S, D
     return;
   }
 
+  // FIXME: The C++11 version of this attribute should error out when it is
+  //        used to specify a weaker alignment, rather than being silently
+  //        ignored. This constraint cannot be applied until we have seen
+  //        all the attributes which apply to the variable.
+
+  if (Attr.getNumArgs() == 0) {
+    D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
+               true, 0, Attr.getAttributeSpellingListIndex()));
+    return;
+  }
+
+  S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
+                   Attr.getAttributeSpellingListIndex());
+}
+
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
+                          unsigned SpellingListIndex) {
+  // FIXME: Handle pack-expansions here.
+  if (DiagnoseUnexpandedParameterPack(E))
+    return;
+
+  AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
+  SourceLocation AttrLoc = AttrRange.getBegin();
+
   // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
-  // FIXME: Use a more reliable mechanism to determine how the attribute was
-  //        spelled.
-  if (Attr.isKeywordAttribute()) {
+  if (TmpAttr.isAlignas()) {
     // C++11 [dcl.align]p1:
     //   An alignment-specifier may be applied to a variable or to a class
     //   data member, but it shall not be applied to a bit-field, a function
@@ -3299,45 +3321,25 @@ static void handleAlignedAttr(Sema &S, D
       if (FD->isBitField())
         DiagKind = 3;
     } else if (!isa<TagDecl>(D)) {
-      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
-        << Attr.getName() << ExpectedVariableFunctionOrTag;
+      Diag(AttrLoc, diag::err_attribute_wrong_decl_type)
+        << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
+        << ExpectedVariableFunctionOrTag;
       return;
     }
     if (DiagKind != -1) {
-      S.Diag(Attr.getLoc(), diag::err_alignas_attribute_wrong_decl_type)
-        << Attr.getName() << DiagKind;
+      Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
+        << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
+        << DiagKind;
       return;
     }
   }
 
-  // FIXME: The C++11 version of this attribute should error out when it is
-  //        used to specify a weaker alignment, rather than being silently
-  //        ignored.
-
-  if (Attr.getNumArgs() == 0) {
-    D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
-               true, 0, Attr.getAttributeSpellingListIndex()));
-    return;
-  }
-
-  S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
-                   Attr.getAttributeSpellingListIndex());
-}
-
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
-                          unsigned SpellingListIndex) {
-  // FIXME: Handle pack-expansions here.
-  if (DiagnoseUnexpandedParameterPack(E))
-    return;
-
   if (E->isTypeDependent() || E->isValueDependent()) {
     // Save dependent expressions in the AST to be instantiated.
-    D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E,
-                                           SpellingListIndex));
+    D->addAttr(::new (Context) AlignedAttr(TmpAttr));
     return;
   }
 
-  SourceLocation AttrLoc = AttrRange.getBegin();
   // FIXME: Cache the number on the Attr object?
   llvm::APSInt Alignment(32);
   ExprResult ICE
@@ -3346,17 +3348,20 @@ void Sema::AddAlignedAttr(SourceRange At
         /*AllowFold*/ false);
   if (ICE.isInvalid())
     return;
-  if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
+
+  // C++11 [dcl.align]p2:
+  //   -- if the constant expression evaluates to zero, the alignment
+  //      specifier shall have no effect
+  // C11 6.7.5p6:
+  //   An alignment specification of zero has no effect.
+  if (!(TmpAttr.isAlignas() && !Alignment) &&
+      !llvm::isPowerOf2_64(Alignment.getZExtValue())) {
     Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
       << E->getSourceRange();
     return;
   }
 
-  AlignedAttr *Attr = ::new (Context) AlignedAttr(AttrRange, Context, true,
-                                                  ICE.take(),
-                                                  SpellingListIndex);
-
-  if (Attr->isDeclspec()) {
+  if (TmpAttr.isDeclspec()) {
     // We've already verified it's a power of 2, now let's make sure it's
     // 8192 or less.
     if (Alignment.getZExtValue() > 8192) {
@@ -3366,7 +3371,8 @@ void Sema::AddAlignedAttr(SourceRange At
     }
   }
 
-  D->addAttr(Attr);
+  D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true,
+                                         ICE.take(), SpellingListIndex));
 }
 
 void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
@@ -3378,6 +3384,42 @@ void Sema::AddAlignedAttr(SourceRange At
   return;
 }
 
+void Sema::CheckAlignasUnderalignment(Decl *D) {
+  assert(D->hasAttrs() && "no attributes on decl");
+
+  QualType Ty;
+  if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+    Ty = VD->getType();
+  else
+    Ty = Context.getTagDeclType(cast<TagDecl>(D));
+  if (Ty->isDependentType())
+    return;
+
+  // C++11 [dcl.align]p5, C11 6.7.5/4:
+  //   The combined effect of all alignment attributes in a declaration shall
+  //   not specify an alignment that is less strict than the alignment that
+  //   would otherwise be required for the entity being declared.
+  AlignedAttr *AlignasAttr = 0;
+  unsigned Align = 0;
+  for (specific_attr_iterator<AlignedAttr>
+         I = D->specific_attr_begin<AlignedAttr>(),
+         E = D->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+    if (I->isAlignmentDependent())
+      return;
+    if (I->isAlignas())
+      AlignasAttr = *I;
+    Align = std::max(Align, I->getAlignment(Context));
+  }
+
+  if (AlignasAttr && Align) {
+    CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
+    CharUnits NaturalAlign = Context.getTypeAlignInChars(Ty);
+    if (NaturalAlign > RequestedAlign)
+      Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned)
+        << Ty << (unsigned)NaturalAlign.getQuantity();
+  }
+}
+
 /// handleModeAttr - This attribute modifies the width of a decl with primitive
 /// type.
 ///

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Feb  1 02:12:08 2013
@@ -347,6 +347,9 @@ Decl *TemplateDeclInstantiator::VisitVar
   }
   SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
 
+  if (Var->hasAttrs())
+    SemaRef.CheckAlignasUnderalignment(Var);
+
   // Link instantiations of static data members back to the template from
   // which they were instantiated.
   if (Var->isStaticDataMember())
@@ -459,6 +462,9 @@ Decl *TemplateDeclInstantiator::VisitFie
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
 
+  if (Field->hasAttrs())
+    SemaRef.CheckAlignasUnderalignment(Field);
+
   if (Invalid)
     Field->setInvalidDecl();
 

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp?rev=174157&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp Fri Feb  1 02:12:08 2013
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -verify %s
+
+alignas(1) int n1; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'int'}}
+alignas(1) alignas(2) int n2; // expected-error {{less than minimum alignment}}
+alignas(1) alignas(2) alignas(4) int n3; // ok
+alignas(1) alignas(2) alignas(0) int n4; // expected-error {{less than minimum alignment}}
+alignas(1) alignas(2) int n5 alignas(4); // ok
+alignas(1) alignas(4) int n6 alignas(2); // ok
+alignas(1) int n7 alignas(2), // expected-error {{less than minimum alignment}}
+               n8 alignas(4); // ok
+alignas(8) int n9 alignas(2); // ok, overaligned
+
+enum alignas(1) E1 {}; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'E1'}}
+enum alignas(1) E2 : char {}; // ok
+enum alignas(4) E3 { e3 = 0 }; // ok
+enum alignas(4) E4 { e4 = 1ull << 33 }; // expected-error {{requested alignment is less than minimum alignment of 8 for type 'E4'}}
+
+struct S1 {
+  alignas(8) int n;
+};
+struct alignas(2) S2 { // expected-error {{requested alignment is less than minimum alignment of 4 for type 'S2'}}
+  int n;
+};
+struct alignas(2) S3 { // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S3'}}
+  S1 s1;
+};
+struct alignas(2) S4 : S1 { // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S4'}}
+};
+struct S5 : S1 {
+  alignas(2) S1 s1; // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S1'}}
+};
+struct S6 {
+  S1 s1;
+};
+struct S7 : S1 {
+};
+struct alignas(2) alignas(8) alignas(1) S8 : S1 {
+};
+
+S1 s1 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S1'}}
+S6 s6 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S6'}}
+S7 s7 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S7'}}
+
+template<int N, int M, typename T>
+struct alignas(N) X { // expected-error 3{{requested alignment is less than minimum}}
+  alignas(M) T t; // expected-error 3{{requested alignment is less than minimum}}
+};
+
+template struct X<1, 1, char>;
+template struct X<4, 1, char>;
+template struct X<1, 2, char>; // expected-note {{instantiation}}
+template struct X<1, 1, short>; // expected-note {{instantiation}}
+template struct X<2, 1, short>; // expected-note {{instantiation}}
+template struct X<2, 2, short>;
+template struct X<16, 8, S1>;
+template struct X<4, 4, S1>; // expected-note {{instantiation}}
+
+template<int N, typename T>
+struct Y {
+  enum alignas(N) E : T {}; // expected-error {{requested alignment is less than minimum}}
+};
+template struct Y<1, char>;
+template struct Y<2, char>;
+template struct Y<1, short>; // expected-note {{instantiation}}
+template struct Y<2, short>;
+
+template<int N, typename T>
+void f() {
+  alignas(N) T v; // expected-error {{requested alignment is less than minimum}}
+};
+template void f<1, char>();
+template void f<2, char>();
+template void f<1, short>(); // expected-note {{instantiation}}
+template void f<2, short>();

Modified: cfe/trunk/test/Sema/alignas.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/alignas.c?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/test/Sema/alignas.c (original)
+++ cfe/trunk/test/Sema/alignas.c Fri Feb  1 02:12:08 2013
@@ -3,7 +3,7 @@
 
 _Alignas(3) int align_illegal; //expected-error {{requested alignment is not a power of 2}}
 _Alignas(int) char align_big;
-_Alignas(1) int align_small; // FIXME: this should be rejected
+_Alignas(1) int align_small; // expected-error {{requested alignment is less than minimum}}
 _Alignas(1) unsigned _Alignas(8) int _Alignas(1) align_multiple;
 
 struct align_member {

Modified: cfe/trunk/test/SemaCXX/attr-cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-cxx0x.cpp?rev=174157&r1=174156&r2=174157&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-cxx0x.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-cxx0x.cpp Fri Feb  1 02:12:08 2013
@@ -2,7 +2,7 @@
 
 int align_illegal alignas(3); //expected-error {{requested alignment is not a power of 2}}
 char align_big alignas(int);
-int align_small alignas(1); // FIXME: this should be rejected
+int align_small alignas(1); // expected-error {{requested alignment is less than minimum}}
 int align_multiple alignas(1) alignas(8) alignas(1);
 alignas(4) int align_before;
 





More information about the cfe-commits mailing list