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();