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/Sema/SemaDeclAttr.cpp | |
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/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 116 |
1 files changed, 79 insertions, 37 deletions
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. /// |