From eefcef89c739e1831406f5e2115c5235aae42470 Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Mon, 15 Dec 2014 18:57:28 +0000 Subject: [PATCH] Warn when attribute 'optnone' conflicts with attributes on a different declaration of the same function. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224256 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/AttrDocs.td | 3 +- include/clang/Basic/DiagnosticSemaKinds.td | 1 + include/clang/Sema/Sema.h | 6 +++ lib/CodeGen/CodeGenModule.cpp | 7 ++-- lib/Sema/SemaDecl.cpp | 6 +++ lib/Sema/SemaDeclAttr.cpp | 49 ++++++++++++++++++++++ test/SemaCXX/attr-optnone.cpp | 18 ++++++++ 7 files changed, 86 insertions(+), 4 deletions(-) diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 13b2b7e06a..918abb6072 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -1264,7 +1264,8 @@ entire application without optimization. Avoiding optimization on the specified function can improve the quality of the debugging information for that function. -This attribute is incompatible with the ``always_inline`` attribute. +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. }]; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 32bf1b067b..22f66bda74 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2608,6 +2608,7 @@ def warn_attribute_protected_visibility : InGroup>; def err_mismatched_visibility: Error<"visibility does not match previous declaration">; def note_previous_attribute : Note<"previous attribute is here">; +def note_conflicting_attribute : Note<"conflicting attribute is here">; def note_attribute : Note<"attribute is here">; def err_mismatched_ms_inheritance : Error< "inheritance model does not match %select{definition|previous declaration}0">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 02aa984da5..b0d9be449a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2005,6 +2005,12 @@ public: int FirstArg, unsigned AttrSpellingListIndex); SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex); + AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); + OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex); /// \brief Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 06467fda6e..87bd955a6c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -769,9 +769,10 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, // OptimizeNone wins over OptimizeForSize, MinSize, AlwaysInline. assert(!F->hasFnAttribute(llvm::Attribute::OptimizeForSize) && "OptimizeNone and OptimizeForSize on same function!"); - // FIXME: Change these to asserts. - F->removeFnAttr(llvm::Attribute::MinSize); - F->removeFnAttr(llvm::Attribute::AlwaysInline); + assert(!F->hasFnAttribute(llvm::Attribute::MinSize) && + "OptimizeNone and MinSize on same function!"); + assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) && + "OptimizeNone and AlwaysInline on same function!"); // Attribute 'inlinehint' has no effect on 'optnone' functions. // Explicitly remove it from the set of function attributes. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f75a2cee63..0d33deaa5e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2154,6 +2154,12 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), AttrSpellingListIndex, IA->getSemanticSpelling()); + else if (const auto *AA = dyn_cast(Attr)) + NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), AttrSpellingListIndex); + else if (const auto *MA = dyn_cast(Attr)) + NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); + else if (const auto *OA = dyn_cast(Attr)) + NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); else if (isa(Attr)) // AlignedAttrs are handled separately, because we need to handle all // such attributes on a declaration at the same time. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 6cc79fff3e..6248f6c78b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3136,6 +3136,55 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (OptimizeNoneAttr *Optnone = D->getAttr()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'always_inline'"; + Diag(Optnone->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + + if (D->hasAttr()) + return nullptr; + + return ::new (Context) AlwaysInlineAttr(Range, Context, + AttrSpellingListIndex); +} + +MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (OptimizeNoneAttr *Optnone = D->getAttr()) { + Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'"; + Diag(Optnone->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + + if (D->hasAttr()) + return nullptr; + + return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex); +} + +OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex) { + if (AlwaysInlineAttr *Inline = D->getAttr()) { + Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline; + Diag(Range.getBegin(), diag::note_conflicting_attribute); + D->dropAttr(); + } + if (MinSizeAttr *MinSize = D->getAttr()) { + Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize; + Diag(Range.getBegin(), diag::note_conflicting_attribute); + D->dropAttr(); + } + + if (D->hasAttr()) + return nullptr; + + return ::new (Context) OptimizeNoneAttr(Range, Context, + AttrSpellingListIndex); +} + static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (checkAttrMutualExclusion(S, D, Attr)) diff --git a/test/SemaCXX/attr-optnone.cpp b/test/SemaCXX/attr-optnone.cpp index e2fce8e239..89ef6c5795 100644 --- a/test/SemaCXX/attr-optnone.cpp +++ b/test/SemaCXX/attr-optnone.cpp @@ -6,9 +6,27 @@ int bar() __attribute__((optnone)) __attribute__((noinline)); int baz() __attribute__((always_inline)) __attribute__((optnone)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}} int quz() __attribute__((optnone)) __attribute__((always_inline)); // expected-error{{'optnone' and 'always_inline' attributes are not compatible}} +__attribute__((always_inline)) int baz1(); // expected-warning{{'always_inline' attribute ignored}} +__attribute__((optnone)) int baz1() { return 1; } // expected-note{{conflicting attribute is here}} + +__attribute__((optnone)) int quz1(); // expected-note{{conflicting attribute is here}} +__attribute__((always_inline)) int quz1() { return 1; } // expected-warning{{'always_inline' attribute ignored}} + int bay() __attribute__((minsize)) __attribute__((optnone)); // expected-error{{'minsize' and 'optnone' attributes are not compatible}} int quy() __attribute__((optnone)) __attribute__((minsize)); // expected-error{{'optnone' and 'minsize' attributes are not compatible}} +__attribute__((minsize)) int bay1(); // expected-warning{{'minsize' attribute ignored}} +__attribute__((optnone)) int bay1() { return 1; } // expected-note{{conflicting attribute is here}} + +__attribute__((optnone)) int quy1(); // expected-note{{conflicting attribute is here}} +__attribute__((minsize)) int quy1() { return 1; } // expected-warning{{'minsize' attribute ignored}} + +__attribute__((always_inline)) // expected-warning{{'always_inline' attribute ignored}} + __attribute__((minsize)) // expected-warning{{'minsize' attribute ignored}} +void bay2(); +__attribute__((optnone)) // expected-note 2 {{conflicting}} +void bay2() {} + __forceinline __attribute__((optnone)) int bax(); // expected-error{{'__forceinline' and 'optnone' attributes are not compatible}} __attribute__((optnone)) __forceinline int qux(); // expected-error{{'optnone' and '__forceinline' attributes are not compatible}}