diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-22 04:55:39 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-02-22 04:55:39 +0000 |
commit | 671b3219c2be00ef8f26234ec993816c3ba56a4f (patch) | |
tree | 9e1b879c18a31c7bd10d6f6e1d8653b21a437056 /lib/Sema/SemaDecl.cpp | |
parent | 1f12c47ae90c03633496d96e79a61762097a4681 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175861 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 196 |
1 files changed, 173 insertions, 23 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 03d18d402d..7e44e6b4bd 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(Sema &S, Decl *New, const Decl *Old) { ++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 *New, Decl *Old, } } - if (mergeDeclAttribute(New, *i, Override)) + if (mergeDeclAttribute(*this, New, *i, Override)) foundAny = true; } + if (mergeAlignedAttrs(*this, New, Old)) + foundAny = true; + if (!foundAny) New->dropAttrs(); } |