summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Robinson <paul_robinson@playstation.sony.com>2015-01-13 18:34:56 +0000
committerPaul Robinson <paul_robinson@playstation.sony.com>2015-01-13 18:34:56 +0000
commit02e4be86fbf4ed585bdb9a624619eebb72d8cf58 (patch)
treec3b45ec9f61f220b651471d7ca57faf656ea5617
parentd775eff4c77cac03406fc6146a162f1f1b076db4 (diff)
When attribute 'optnone' appears on the same declaration with a
conflicting attribute, warn about the conflict and pick a "winning" attribute to preserve, instead of emitting an error. This matches the behavior when the conflicting attributes are on different declarations. Along the way I discovered that conflicts involving __forceinline were reported as 'always_inline' (alternate spelling, same attribute) so fixed that up to report the attribute as spelled in the source. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@225813 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDecl.cpp4
-rw-r--r--lib/Sema/SemaDeclAttr.cpp36
-rw-r--r--test/SemaCXX/attr-optnone.cpp21
4 files changed, 30 insertions, 32 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 2ba74b12f6..74efa60c93 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2009,6 +2009,7 @@ public:
SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
unsigned AttrSpellingListIndex);
AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
unsigned AttrSpellingListIndex);
MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index baa6822da7..7d1e28ee59 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2155,7 +2155,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
AttrSpellingListIndex,
IA->getSemanticSpelling());
else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
- NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), AttrSpellingListIndex);
+ NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(),
+ &S.Context.Idents.get(AA->getSpelling()),
+ AttrSpellingListIndex);
else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index aec387e6db..17a849ea7a 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -3141,9 +3141,10 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
+ IdentifierInfo *Ident,
unsigned AttrSpellingListIndex) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'always_inline'";
+ Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident;
Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
@@ -3191,34 +3192,23 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- AlwaysInlineAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
+ D, Attr.getRange(), Attr.getName(),
+ Attr.getAttributeSpellingListIndex()))
+ D->addAttr(Inline);
}
-static void handleMinSizeAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
- if (checkAttrMutualExclusion<OptimizeNoneAttr>(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- MinSizeAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(
+ D, Attr.getRange(), Attr.getAttributeSpellingListIndex()))
+ D->addAttr(MinSize);
}
static void handleOptimizeNoneAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
- return;
- if (checkAttrMutualExclusion<MinSizeAttr>(S, D, Attr))
- return;
-
- D->addAttr(::new (S.Context)
- OptimizeNoneAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(
+ D, Attr.getRange(), Attr.getAttributeSpellingListIndex()))
+ D->addAttr(Optnone);
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
diff --git a/test/SemaCXX/attr-optnone.cpp b/test/SemaCXX/attr-optnone.cpp
index 89ef6c5795..58776caf7a 100644
--- a/test/SemaCXX/attr-optnone.cpp
+++ b/test/SemaCXX/attr-optnone.cpp
@@ -3,8 +3,8 @@
int foo() __attribute__((optnone));
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}}
+int baz() __attribute__((always_inline)) __attribute__((optnone)); // expected-warning{{'always_inline' attribute ignored}} expected-note{{conflicting attribute is here}}
+int quz() __attribute__((optnone)) __attribute__((always_inline)); // expected-warning{{'always_inline' attribute ignored}} expected-note{{conflicting attribute is here}}
__attribute__((always_inline)) int baz1(); // expected-warning{{'always_inline' attribute ignored}}
__attribute__((optnone)) int baz1() { return 1; } // expected-note{{conflicting attribute is here}}
@@ -12,8 +12,8 @@ __attribute__((optnone)) int baz1() { return 1; } // expected-note{{conflicting
__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}}
+int bay() __attribute__((minsize)) __attribute__((optnone)); // expected-warning{{'minsize' attribute ignored}} expected-note{{conflicting}}
+int quy() __attribute__((optnone)) __attribute__((minsize)); // expected-warning{{'minsize' attribute ignored}} expected-note{{conflicting}}
__attribute__((minsize)) int bay1(); // expected-warning{{'minsize' attribute ignored}}
__attribute__((optnone)) int bay1() { return 1; } // expected-note{{conflicting attribute is here}}
@@ -27,8 +27,13 @@ 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}}
+__forceinline __attribute__((optnone)) int bax(); // expected-warning{{'__forceinline' attribute ignored}} expected-note{{conflicting}}
+__attribute__((optnone)) __forceinline int qux(); // expected-warning{{'__forceinline' attribute ignored}} expected-note{{conflicting}}
+
+__forceinline int bax2(); // expected-warning{{'__forceinline' attribute ignored}}
+__attribute__((optnone)) int bax2() { return 1; } // expected-note{{conflicting}}
+__attribute__((optnone)) int qux2(); // expected-note{{conflicting}}
+__forceinline int qux2() { return 1; } // expected-warning{{'__forceinline' attribute ignored}}
int globalVar __attribute__((optnone)); // expected-warning{{'optnone' attribute only applies to functions}}
@@ -50,8 +55,8 @@ int foo2();
[[clang::optnone]]
int bar2() __attribute__((noinline));
-[[clang::optnone]]
-int baz2() __attribute__((always_inline)); // expected-error{{'always_inline' and 'optnone' attributes are not compatible}}
+[[clang::optnone]] // expected-note {{conflicting}}
+int baz2() __attribute__((always_inline)); // expected-warning{{'always_inline' attribute ignored}}
[[clang::optnone]] int globalVar2; //expected-warning{{'optnone' attribute only applies to functions}}