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.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174157 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 834041c..4404c6f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4611,6 +4611,9 @@
   // 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 @@
 
   // 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 @@
     if (!Completed)
       Record->completeDefinition();
 
+    if (Record->hasAttrs())
+      CheckAlignasUnderalignment(Record);
   } else {
     ObjCIvarDecl **ClsFields =
       reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -11427,6 +11436,10 @@
     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,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 8500bff..9409b30 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -3272,10 +3272,32 @@
     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 @@
       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 @@
         /*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 @@
     }
   }
 
-  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 @@
   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.
 ///
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c146e9d..2d3d0bd 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -347,6 +347,9 @@
   }
   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 @@
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
 
+  if (Field->hasAttrs())
+    SemaRef.CheckAlignasUnderalignment(Field);
+
   if (Invalid)
     Field->setInvalidDecl();