diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-01 08:12:08 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-01 08:12:08 +0000 |
commit | be507b6e72df8ab5e7d8c31eb4453e1bdf5fcfaf (patch) | |
tree | 7026e3f1c0568f199366c217a61ef5a268916cff /lib | |
parent | 5ccd3d0214b9d765a1bb41872da27d3c5530ab2b (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 116 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 |
3 files changed, 99 insertions, 38 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 834041c65c..4404c6f9a0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4611,6 +4611,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // 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 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // 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 @@ void Sema::ActOnFields(Scope* S, if (!Completed) Record->completeDefinition(); + if (Record->hasAttrs()) + CheckAlignasUnderalignment(Record); } else { ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); @@ -11427,6 +11436,10 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, 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 8500bff6bc..9409b30e5b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3272,10 +3272,32 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { 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 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, /*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 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } } - 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 @@ 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. /// diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index c146e9dd44..2d3d0bd5b6 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -347,6 +347,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { } 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 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope); + if (Field->hasAttrs()) + SemaRef.CheckAlignasUnderalignment(Field); + if (Invalid) Field->setInvalidDecl(); |