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