Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2464,6 +2464,11 @@ void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); + void mergeDeclAttributes2(NamedDecl *New, Decl *Old, + AvailabilityMergeKind AMK = AMK_Redeclaration); + void mergeDeclAttributes3(NamedDecl *New, const AttrVec &AttrList, + bool OldIsUsed, SourceLocation OldLocation, + AvailabilityMergeKind AMK = AMK_Redeclaration); void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -836,6 +836,15 @@ getASTContext().eraseDeclAttrs(this); } +void Decl::addAttr(Attr *A) { + if (!hasAttrs()) { + setAttrs(AttrVec(1, A)); + return; + } + + getAttrs().push_back(A); +} + const AttrVec &Decl::getAttrs() const { assert(HasAttrs && "No attrs to get!"); return getASTContext().getDeclAttrs(this); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2413,6 +2413,114 @@ return AnyAdded; } +static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, + ArrayRef AlignedAttrs) { + // Look for alignas attributes on Old, and pick out whichever attribute + // specifies the strictest alignment requirement. + AlignedAttr *OldAlignasAttr = nullptr; + AlignedAttr *OldStrictestAlignAttr = nullptr; + unsigned OldAlign = 0; + for (auto *I : AlignedAttrs) { + // FIXME: We have no way of representing inherited dependent alignments + // in a case like: + // template struct alignas(A) X; + // template 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 = nullptr; + unsigned NewAlign = 0; + for (auto *I : New->specific_attrs()) { + 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(New)) + Ty = VD->getType(); + else + Ty = S.Context.getTagDeclType(cast(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; + S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration) + << OldAlignasAttr; + } + + 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, const InheritableAttr *Attr, Sema::AvailabilityMergeKind AMK) { @@ -2618,6 +2726,116 @@ /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK) { + AttrVec Attrs = New->hasAttrs() ? New->getAttrs() : AttrVec(); + bool OldIsUsed = Old->isUsed(); + New->dropAttrs(); + New->setAttrs(AttrVec()); + + // Propagate inherited attributes. + mergeDeclAttributes2(New, Old, AMK); + mergeDeclAttributes3(New, Attrs, OldIsUsed, Old->getLocation(), AMK); + + if (New->getAttrs().empty()) + New->dropAttrs(); +} + +template T *getSpecificAttr(const AttrVec &AttrList) { + for (auto A : AttrList) { + if (isa(A)) + return cast(A); + } + return nullptr; +} + +void Sema::mergeDeclAttributes3(NamedDecl *New, const AttrVec &AttrList, + bool OldIsUsed, SourceLocation OldLocation, + AvailabilityMergeKind AMK) { + SmallVector AlignedAttrs; + + if (AsmLabelAttr *NewA = getSpecificAttr(AttrList)) { + if (AsmLabelAttr *OldA = New->getAttr()) { + if (OldA->getLabel() != NewA->getLabel()) { + // This redeclaration changes __asm__ label. + Diag(New->getLocation(), diag::err_different_asm_label); + Diag(OldA->getLocation(), diag::note_previous_declaration); + } + } else if (OldIsUsed) { + // This redeclaration adds an __asm__ label to a declaration that has + // already been ODR-used. + Diag(New->getLocation(), diag::err_late_asm_label_name) + << isa(New) << New->getAttr()->getRange(); + } + } + + // Re-declaration cannot add abi_tag's. + if (const auto *NewAbiTagAttr = getSpecificAttr(AttrList)) { + if (const auto *OldAbiTagAttr = New->getAttr()) { + for (const auto &NewTag : NewAbiTagAttr->tags()) { + if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(), + NewTag) == OldAbiTagAttr->tags_end()) { + Diag(NewAbiTagAttr->getLocation(), + diag::err_new_abi_tag_on_redeclaration) + << NewTag; + Diag(OldAbiTagAttr->getLocation(), diag::note_previous_declaration); + } + } + } else { + Diag(OldAbiTagAttr->getLocation(), diag::err_abi_tag_on_redeclaration); + Diag(OldLocation, diag::note_previous_declaration); + } + } + + // This redeclaration adds a section attribute. + if (New->hasAttr() && !getSpecificAttr(AttrList)) { + if (auto *VD = dyn_cast(New)) { + if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) { + Diag(New->getLocation(), diag::warn_attribute_section_on_redeclaration); + Diag(OldLocation, diag::note_previous_declaration); + } + } + } + + for (auto Attr : AttrList) { + if (!isa(Attr)) { + New->addAttr(Attr); + continue; + } + + if (auto AA = dyn_cast(Attr)) { + AlignedAttrs.push_back(AA); + continue; + } + + auto *I = cast(Attr); + + // Already handled. + if (isa(I)) + continue; + + // Ignore deprecated/unavailable/availability attributes if requested. + AvailabilityMergeKind LocalAMK = AMK_None; + if (isa(I) || isa(I) || + isa(I)) { + switch (AMK) { + case AMK_None: + continue; + + case AMK_Redeclaration: + case AMK_Override: + case AMK_ProtocolImplementation: + LocalAMK = AMK; + break; + } + } + + mergeDeclAttribute(*this, New, I, LocalAMK); + } + + mergeAlignedAttrs(*this, New, AlignedAttrs); +} + +void Sema::mergeDeclAttributes2(NamedDecl *New, Decl *Old, + AvailabilityMergeKind AMK) { if (UsedAttr *OldAttr = Old->getMostRecentDecl()->getAttr()) { UsedAttr *NewAttr = OldAttr->clone(Context); NewAttr->setInherited(true); Index: test/Misc/ast-dump-attr.cpp =================================================================== --- test/Misc/ast-dump-attr.cpp +++ test/Misc/ast-dump-attr.cpp @@ -208,4 +208,4 @@ i = reinterpret_cast(7); } } -} +}