Also support alignas(0), which C++11 and C11 require us to ignore.
llvm-svn: 174157
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">]>];
}
"%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<
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,
// 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]."
// 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))
if (!Completed)
Record->completeDefinition();
+ if (Record->hasAttrs())
+ CheckAlignasUnderalignment(Record);
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
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,
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
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
/*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) {
}
}
- D->addAttr(Attr);
+ D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true,
+ ICE.take(), SpellingListIndex));
}
void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
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.
///
}
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())
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
+ if (Field->hasAttrs())
+ SemaRef.CheckAlignasUnderalignment(Field);
+
if (Invalid)
Field->setInvalidDecl();
--- /dev/null
+// 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>();
_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 {
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;