r175861 - Implement C++11 [dcl.align]p6-p8, and C11 6.7.5/7. This had to be split out of

Richard Smith richard-llvm at metafoo.co.uk
Thu Feb 21 20:55:39 PST 2013


Author: rsmith
Date: Thu Feb 21 22:55:39 2013
New Revision: 175861

URL: http://llvm.org/viewvc/llvm-project?rev=175861&view=rev
Log:
Implement C++11 [dcl.align]p6-p8, and C11 6.7.5/7. This had to be split out of
the normal attribute-merging path, because we can't merge alignment attributes
without knowing the complete set of alignment attributes which apply to a
particular declaration.

Added:
    cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp
Modified:
    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

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=175861&r1=175860&r2=175861&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 21 22:55:39 2013
@@ -1652,9 +1652,16 @@ def err_attribute_argument_not_int : Err
 def err_aligned_attribute_argument_not_int : Error<
   "'aligned' attribute requires integer constant">;
 def err_alignas_attribute_wrong_decl_type : Error<
-  "%0 attribute cannot be applied to a %select{"
+  "'%select{alignas|_Alignas}0' attribute cannot be applied to a %select{"
   "function parameter|variable with 'register' storage class|"
   "'catch' variable|bit-field}1">;
+def err_alignas_missing_on_definition : Error<
+  "'%select{alignas|_Alignas}0' must be specified on definition if it is "
+  "specified on any declaration">;
+def note_alignas_on_declaration : Note<
+  "declared with '%select{alignas|_Alignas}0' attribute here">;
+def err_alignas_mismatch : Error<
+  "redeclaration has different alignment requirement (%1 vs %0)">;
 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<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=175861&r1=175860&r2=175861&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb 21 22:55:39 2013
@@ -1705,8 +1705,6 @@ public:
                               unsigned AttrSpellingListIndex);
   SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
                                 unsigned AttrSpellingListIndex);
-  bool mergeDeclAttribute(NamedDecl *New, InheritableAttr *Attr,
-                          bool Override);
 
   /// \brief Describes the kind of merge to perform for availability
   /// attributes (including "deprecated", "unavailable", and "availability").

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=175861&r1=175860&r2=175861&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb 21 22:55:39 2013
@@ -1822,37 +1822,164 @@ DeclHasAttr(const Decl *D, const Attr *A
   return false;
 }
 
-bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr,
-                              bool Override) {
+static bool isAttributeTargetADefinition(Decl *D) {
+  if (VarDecl *VD = dyn_cast<VarDecl>(D))
+    return VD->isThisDeclarationADefinition();
+  if (TagDecl *TD = dyn_cast<TagDecl>(D))
+    return TD->isCompleteDefinition() || TD->isBeingDefined();
+  return true;
+}
+
+/// Merge alignment attributes from \p Old to \p New, taking into account the
+/// special semantics of C11's _Alignas specifier and C++11's alignas attribute.
+///
+/// \return \c true if any attributes were added to \p New.
+static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
+  // Look for alignas attributes on Old, and pick out whichever attribute
+  // specifies the strictest alignment requirement.
+  AlignedAttr *OldAlignasAttr = 0;
+  AlignedAttr *OldStrictestAlignAttr = 0;
+  unsigned OldAlign = 0;
+  for (specific_attr_iterator<AlignedAttr>
+         I = Old->specific_attr_begin<AlignedAttr>(),
+         E = Old->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+    // FIXME: We have no way of representing inherited dependent alignments
+    // in a case like:
+    //   template<int A, int B> struct alignas(A) X;
+    //   template<int A, int B> struct alignas(B) X {};
+    // For now, we just ignore any alignas attributes which are not on the
+    // definition in such a case.
+    if (I->isAlignmentDependent())
+      return false;
+
+    if (I->isAlignas())
+      OldAlignasAttr = *I;
+
+    unsigned Align = I->getAlignment(S.Context);
+    if (Align > OldAlign) {
+      OldAlign = Align;
+      OldStrictestAlignAttr = *I;
+    }
+  }
+
+  // Look for alignas attributes on New.
+  AlignedAttr *NewAlignasAttr = 0;
+  unsigned NewAlign = 0;
+  for (specific_attr_iterator<AlignedAttr>
+         I = New->specific_attr_begin<AlignedAttr>(),
+         E = New->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+    if (I->isAlignmentDependent())
+      return false;
+
+    if (I->isAlignas())
+      NewAlignasAttr = *I;
+
+    unsigned Align = I->getAlignment(S.Context);
+    if (Align > NewAlign)
+      NewAlign = Align;
+  }
+
+  if (OldAlignasAttr && NewAlignasAttr && OldAlign != NewAlign) {
+    // Both declarations have 'alignas' attributes. We require them to match.
+    // C++11 [dcl.align]p6 and C11 6.7.5/7 both come close to saying this, but
+    // fall short. (If two declarations both have alignas, they must both match
+    // every definition, and so must match each other if there is a definition.)
+
+    // If either declaration only contains 'alignas(0)' specifiers, then it
+    // specifies the natural alignment for the type.
+    if (OldAlign == 0 || NewAlign == 0) {
+      QualType Ty;
+      if (ValueDecl *VD = dyn_cast<ValueDecl>(New))
+        Ty = VD->getType();
+      else
+        Ty = S.Context.getTagDeclType(cast<TagDecl>(New));
+
+      if (OldAlign == 0)
+        OldAlign = S.Context.getTypeAlign(Ty);
+      if (NewAlign == 0)
+        NewAlign = S.Context.getTypeAlign(Ty);
+    }
+
+    if (OldAlign != NewAlign) {
+      S.Diag(NewAlignasAttr->getLocation(), diag::err_alignas_mismatch)
+        << (unsigned)S.Context.toCharUnitsFromBits(OldAlign).getQuantity()
+        << (unsigned)S.Context.toCharUnitsFromBits(NewAlign).getQuantity();
+      S.Diag(OldAlignasAttr->getLocation(), diag::note_previous_declaration);
+    }
+  }
+
+  if (OldAlignasAttr && !NewAlignasAttr && isAttributeTargetADefinition(New)) {
+    // C++11 [dcl.align]p6:
+    //   if any declaration of an entity has an alignment-specifier,
+    //   every defining declaration of that entity shall specify an
+    //   equivalent alignment.
+    // C11 6.7.5/7:
+    //   If the definition of an object does not have an alignment
+    //   specifier, any other declaration of that object shall also
+    //   have no alignment specifier.
+    S.Diag(New->getLocation(), diag::err_alignas_missing_on_definition)
+      << OldAlignasAttr->isC11();
+    S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration)
+      << OldAlignasAttr->isC11();
+  }
+
+  bool AnyAdded = false;
+
+  // Ensure we have an attribute representing the strictest alignment.
+  if (OldAlign > NewAlign) {
+    AlignedAttr *Clone = OldStrictestAlignAttr->clone(S.Context);
+    Clone->setInherited(true);
+    New->addAttr(Clone);
+    AnyAdded = true;
+  }
+
+  // Ensure we have an alignas attribute if the old declaration had one.
+  if (OldAlignasAttr && !NewAlignasAttr &&
+      !(AnyAdded && OldStrictestAlignAttr->isAlignas())) {
+    AlignedAttr *Clone = OldAlignasAttr->clone(S.Context);
+    Clone->setInherited(true);
+    New->addAttr(Clone);
+    AnyAdded = true;
+  }
+
+  return AnyAdded;
+}
+
+static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
+                               bool Override) {
   InheritableAttr *NewAttr = NULL;
   unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
   if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
-    NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
-                                    AA->getIntroduced(), AA->getDeprecated(),
-                                    AA->getObsoleted(), AA->getUnavailable(),
-                                    AA->getMessage(), Override,
-                                    AttrSpellingListIndex);
+    NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
+                                      AA->getIntroduced(), AA->getDeprecated(),
+                                      AA->getObsoleted(), AA->getUnavailable(),
+                                      AA->getMessage(), Override,
+                                      AttrSpellingListIndex);
   else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
-    NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
-                                  AttrSpellingListIndex);
+    NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+                                    AttrSpellingListIndex);
   else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
-    NewAttr = mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
-                                      AttrSpellingListIndex);
+    NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+                                        AttrSpellingListIndex);
   else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
-    NewAttr = mergeDLLImportAttr(D, ImportA->getRange(),
-                                 AttrSpellingListIndex);
+    NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
+                                   AttrSpellingListIndex);
   else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
-    NewAttr = mergeDLLExportAttr(D, ExportA->getRange(),
-                                 AttrSpellingListIndex);
+    NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
+                                   AttrSpellingListIndex);
   else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
-    NewAttr = mergeFormatAttr(D, FA->getRange(), FA->getType(),
-                              FA->getFormatIdx(), FA->getFirstArg(),
-                              AttrSpellingListIndex);
+    NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
+                                FA->getFormatIdx(), FA->getFirstArg(),
+                                AttrSpellingListIndex);
   else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
-    NewAttr = mergeSectionAttr(D, SA->getRange(), SA->getName(),
-                               AttrSpellingListIndex);
+    NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
+                                 AttrSpellingListIndex);
+  else if (isa<AlignedAttr>(Attr))
+    // AlignedAttrs are handled separately, because we need to handle all
+    // such attributes on a declaration at the same time.
+    NewAttr = 0;
   else if (!DeclHasAttr(D, Attr))
-    NewAttr = cast<InheritableAttr>(Attr->clone(Context));
+    NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
 
   if (NewAttr) {
     NewAttr->setInherited(true);
@@ -1903,11 +2030,31 @@ static void checkNewAttributesAfterDef(S
       ++I;
       continue; // regular attr merging will take care of validating this.
     }
-    // C's _Noreturn is allowed to be added to a function after it is defined.
+
     if (isa<C11NoReturnAttr>(NewAttribute)) {
+      // C's _Noreturn is allowed to be added to a function after it is defined.
       ++I;
       continue;
+    } else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
+      if (AA->isAlignas()) { 
+        // C++11 [dcl.align]p6:
+        //   if any declaration of an entity has an alignment-specifier,
+        //   every defining declaration of that entity shall specify an
+        //   equivalent alignment.
+        // C11 6.7.5/7:
+        //   If the definition of an object does not have an alignment
+        //   specifier, any other declaration of that object shall also
+        //   have no alignment specifier.
+        S.Diag(Def->getLocation(), diag::err_alignas_missing_on_definition)
+          << AA->isC11();
+        S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration)
+          << AA->isC11();
+        NewAttributes.erase(NewAttributes.begin() + I);
+        --E;
+        continue;
+      }
     }
+
     S.Diag(NewAttribute->getLocation(),
            diag::warn_attribute_precede_definition);
     S.Diag(Def->getLocation(), diag::note_previous_definition);
@@ -1956,10 +2103,13 @@ void Sema::mergeDeclAttributes(NamedDecl
       }
     }
 
-    if (mergeDeclAttribute(New, *i, Override))
+    if (mergeDeclAttribute(*this, New, *i, Override))
       foundAny = true;
   }
 
+  if (mergeAlignedAttrs(*this, New, Old))
+    foundAny = true;
+
   if (!foundAny) New->dropAttrs();
 }
 

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=175861&r1=175860&r2=175861&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Feb 21 22:55:39 2013
@@ -3368,8 +3368,7 @@ void Sema::AddAlignedAttr(SourceRange At
     }
     if (DiagKind != -1) {
       Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
-        << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
-        << DiagKind;
+        << TmpAttr.isC11() << DiagKind;
       return;
     }
   }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=175861&r1=175860&r2=175861&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Feb 21 22:55:39 2013
@@ -322,6 +322,11 @@ Decl *TemplateDeclInstantiator::VisitVar
     Var->setReferenced(D->isReferenced());
   }
 
+  SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
+
+  if (Var->hasAttrs())
+    SemaRef.CheckAlignasUnderalignment(Var);
+
   // FIXME: In theory, we could have a previous declaration for variables that
   // are not static data members.
   // FIXME: having to fake up a LookupResult is dumb.
@@ -345,10 +350,6 @@ Decl *TemplateDeclInstantiator::VisitVar
     if (Owner->isFunctionOrMethod())
       SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
   }
-  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.

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp?rev=175861&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp Thu Feb 21 22:55:39 2013
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+alignas(4) extern int n1; // expected-note {{previous declaration}}
+alignas(8) int n1; // expected-error {{redeclaration has different alignment requirement (8 vs 4)}}
+
+alignas(8) int n2; // expected-note {{previous declaration}}
+alignas(4) extern int n2; // expected-error {{different alignment requirement (4 vs 8)}}
+
+alignas(8) extern int n3; // expected-note {{previous declaration}}
+alignas(4) extern int n3; // expected-error {{different alignment requirement (4 vs 8)}}
+
+extern int n4;
+alignas(8) extern int n4;
+
+alignas(8) extern int n5;
+extern int n5;
+
+int n6; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+alignas(8) extern int n6; // expected-note {{declared with 'alignas' attribute here}}
+
+extern int n7;
+alignas(8) int n7;
+
+alignas(8) extern int n8; // expected-note {{declared with 'alignas' attribute here}}
+int n8; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+int n9; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+alignas(4) extern int n9; // expected-note {{declared with 'alignas' attribute here}}
+
+
+enum alignas(2) E : char; // expected-note {{declared with 'alignas' attribute here}}
+enum E : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+enum alignas(4) F : char; // expected-note {{previous declaration is here}}
+enum alignas(2) F : char; // expected-error {{redeclaration has different alignment requirement (2 vs 4)}}
+
+enum G : char;
+enum alignas(8) G : char {};
+enum G : char;
+
+enum H : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+enum alignas(1) H : char; // expected-note {{declared with 'alignas' attribute here}}
+
+
+struct S;
+struct alignas(16) S; // expected-note {{declared with 'alignas' attribute here}}
+struct S;
+struct S { int n; }; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+struct alignas(2) T;
+struct alignas(2) T { char c; }; // expected-note {{previous declaration is here}}
+struct T;
+struct alignas(4) T; // expected-error {{redeclaration has different alignment requirement (4 vs 2)}}
+
+struct U;
+struct alignas(2) U {};
+
+struct V {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+struct alignas(1) V; // expected-note {{declared with 'alignas' attribute here}}
+
+template<int M, int N> struct alignas(M) W;
+template<int M, int N> struct alignas(N) W {};
+W<4,4> w44; // ok
+// FIXME: We should reject this.
+W<1,2> w12;
+static_assert(alignof(W<4,4>) == 4, "");
+
+template<int M, int N, int O, int P> struct X {
+  alignas(M) alignas(N) static char Buffer[32]; // expected-note {{previous declaration is here}}
+};
+template<int M, int N, int O, int P>
+alignas(O) alignas(P) char X<M, N, O, P>::Buffer[32]; // expected-error {{redeclaration has different alignment requirement (8 vs 2)}}
+char *x1848 = X<1,8,4,8>::Buffer; // ok
+char *x1248 = X<1,2,4,8>::Buffer; // expected-note {{in instantiation of}}
+
+template<int M, int N, int O, int P> struct Y {
+  enum alignas(M) alignas(N) E : char;
+};
+template<int M, int N, int O, int P>
+enum alignas(O) alignas(P) Y<M,N,O,P>::E : char { e };
+int y1848 = Y<1,8,4,8>::e;
+// FIXME: We should reject this.
+int y1248 = Y<1,2,4,8>::e;

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp?rev=175861&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp Thu Feb 21 22:55:39 2013
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T, typename A, int N> struct X {
+  alignas(T) alignas(A) T buffer[N];
+};
+
+static_assert(alignof(X<char, int, sizeof(int)>) == alignof(int), "");
+static_assert(alignof(X<int, char, 1>) == alignof(int), "");
+
+
+template<typename T, typename A, int N> struct Y {
+  alignas(A) T buffer[N]; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'int [1]'}}
+};
+
+static_assert(alignof(Y<char, int, sizeof(int)>) == alignof(int), "");
+static_assert(alignof(Y<int, char, 1>) == alignof(int), ""); // expected-note {{in instantiation of}}

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp?rev=175861&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp Thu Feb 21 22:55:39 2013
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+alignas(double) void f(); // expected-error {{'alignas' attribute only applies to variables, data members and tag types}}
+alignas(double) unsigned char c[sizeof(double)]; // expected-note {{previous}}
+extern unsigned char c[sizeof(double)];
+alignas(float) extern unsigned char c[sizeof(double)]; // expected-error {{different alignment}}





More information about the cfe-commits mailing list