[clang] 8995ccc - [Clang] Add support for [[msvc::noinline]] attribute. (#91720)
via cfe-commits
cfe-commits at lists.llvm.org
Tue May 28 06:29:36 PDT 2024
Author: Xu Zhang
Date: 2024-05-28T06:29:31-07:00
New Revision: 8995ccc4460ed8a90dcc9bd023743a8f59458f50
URL: https://github.com/llvm/llvm-project/commit/8995ccc4460ed8a90dcc9bd023743a8f59458f50
DIFF: https://github.com/llvm/llvm-project/commit/8995ccc4460ed8a90dcc9bd023743a8f59458f50.diff
LOG: [Clang] Add support for [[msvc::noinline]] attribute. (#91720)
Fixes #90941.
Add support for ``[[msvc::noinline]]`` attribute, which is actually an
alias of ``[[clang::noinline]]``.
Added:
Modified:
clang/include/clang/Basic/Attr.td
clang/lib/Sema/SemaStmtAttr.cpp
clang/test/CodeGen/attr-noinline.cpp
clang/test/Sema/attr-noinline.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index e59cccccdd369..ef9df1e9d8b4a 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2025,9 +2025,12 @@ def Convergent : InheritableAttr {
def NoInline : DeclOrStmtAttr {
let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">,
CXX11<"clang", "noinline">, C23<"clang", "noinline">,
+ CXX11<"msvc", "noinline">, C23<"msvc", "noinline">,
Declspec<"noinline">];
- let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">,
- C23<"clang", "noinline">]>];
+ let Accessors = [Accessor<"isStmtNoInline", [CXX11<"clang", "noinline">,
+ C23<"clang", "noinline">,
+ CXX11<"msvc", "noinline">,
+ C23<"msvc", "noinline">]>];
let Documentation = [NoInlineDocs];
let Subjects = SubjectList<[Function, Stmt], WarnDiag,
"functions and statements">;
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 8735d96c84079..82373fe96a824 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -285,7 +285,7 @@ bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
NoInlineAttr NIA(S.Context, A);
- if (!NIA.isClangNoInline()) {
+ if (!NIA.isStmtNoInline()) {
S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
<< "[[clang::noinline]]";
return nullptr;
diff --git a/clang/test/CodeGen/attr-noinline.cpp b/clang/test/CodeGen/attr-noinline.cpp
index f0588cfecf463..c1fb9941b5251 100644
--- a/clang/test/CodeGen/attr-noinline.cpp
+++ b/clang/test/CodeGen/attr-noinline.cpp
@@ -9,6 +9,7 @@ static int baz(int x) {
}
[[clang::noinline]] bool noi() { }
+[[msvc::noinline]] bool ms_noi() { return true; }
void foo(int i) {
[[clang::noinline]] bar();
@@ -39,6 +40,31 @@ void foo(int i) {
// CHECK: call noundef zeroext i1 @_Z3barv()
}
+void ms_noi_check(int i) {
+ [[msvc::noinline]] bar();
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR:[0-9]+]]
+ [[msvc::noinline]] i = baz(i);
+// CHECK: call noundef i32 @_ZL3bazi({{.*}}) #[[NOINLINEATTR]]
+ [[msvc::noinline]] (i = 4, bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+ [[msvc::noinline]] (void)(bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+ [[msvc::noinline]] f(bar(), bar());
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+// CHECK: call void @_Z1fbb({{.*}}) #[[NOINLINEATTR]]
+ [[msvc::noinline]] [] { bar(); bar(); }(); // noinline only applies to the anonymous function call
+// CHECK: call void @"_ZZ12ms_noi_checkiENK3$_0clEv"(ptr {{[^,]*}} %ref.tmp) #[[NOINLINEATTR]]
+ [[msvc::noinline]] for (bar(); bar(); bar()) {}
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
+ [[msvc::noinline]] ms_noi();
+// CHECK: call noundef zeroext i1 @_Z6ms_noiv()
+ ms_noi();
+// CHECK: call noundef zeroext i1 @_Z6ms_noiv()
+}
+
struct S {
friend bool operator==(const S &LHS, const S &RHS);
};
@@ -50,6 +76,12 @@ void func(const S &s1, const S &s2) {
bool b;
[[clang::noinline]] b = s1 == s2;
// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
+
+ [[msvc::noinline]]g(s1 == s2);
+// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
+// CHECK: call void @_Z1gb({{.*}}) #[[NOINLINEATTR]]
+ [[msvc::noinline]] b = s1 == s2;
+// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
}
// CHECK: attributes #[[NOINLINEATTR]] = { noinline }
diff --git a/clang/test/Sema/attr-noinline.cpp b/clang/test/Sema/attr-noinline.cpp
index bd6505b9fe98e..6da0e873af1b6 100644
--- a/clang/test/Sema/attr-noinline.cpp
+++ b/clang/test/Sema/attr-noinline.cpp
@@ -2,9 +2,9 @@
int bar();
-// expected-note at +1{{conflicting attribute is here}}
+// expected-note at +1 2 {{conflicting attribute is here}}
[[gnu::always_inline]] void always_inline_fn(void) { }
-// expected-note at +1{{conflicting attribute is here}}
+// expected-note at +1 2 {{conflicting attribute is here}}
[[gnu::flatten]] void flatten_fn(void) { }
[[gnu::noinline]] void noinline_fn(void) { }
@@ -25,7 +25,21 @@ void foo() {
__attribute__((noinline)) bar(); // expected-warning {{attribute is ignored on this statement as it only applies to functions; use '[[clang::noinline]]' on statements}}
}
+void ms_noi_check() {
+ [[msvc::noinline]] bar();
+ [[msvc::noinline(0)]] bar(); // expected-error {{'noinline' attribute takes no arguments}}
+ int x;
+ [[msvc::noinline]] x = 0; // expected-warning {{'noinline' attribute is ignored because there exists no call expression inside the statement}}
+ [[msvc::noinline]] { asm("nop"); } // expected-warning {{'noinline' attribute is ignored because there exists no call expression inside the statement}}
+ [[msvc::noinline]] label: x = 1; // expected-warning {{'noinline' attribute only applies to functions and statements}}
+
+ [[msvc::noinline]] always_inline_fn(); // expected-warning {{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ [[msvc::noinline]] flatten_fn(); // expected-warning {{statement attribute 'noinline' has higher precedence than function attribute 'flatten'}}
+ [[msvc::noinline]] noinline_fn();
+}
+
[[clang::noinline]] static int i = bar(); // expected-warning {{'noinline' attribute only applies to functions and statements}}
+[[msvc::noinline]] static int j = bar(); // expected-warning {{'noinline' attribute only applies to functions and statements}}
// This used to crash the compiler.
template<int D>
@@ -69,7 +83,39 @@ int variadic_baz(int x) {
[[clang::noinline]] return non_dependent(x) + (dependent<D>(x) + ...);
}
+template<int D> [[clang::always_inline]]
+int qux(int x) { // #QUX
+ // expected-warning at +2{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ // expected-note@#NO_DEP{{conflicting attribute is here}}
+ [[msvc::noinline]] non_dependent(x);
+ if constexpr (D>0) {
+ // expected-warning at +6{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ // expected-note@#NO_DEP{{conflicting attribute is here}}
+ // expected-warning at +4 3{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ // expected-note@#QUX 3{{conflicting attribute is here}}
+ // expected-note@#QUX_INST 3{{in instantiation}}
+ // expected-note at +1 3{{in instantiation}}
+ [[msvc::noinline]] return non_dependent(x), qux<D-1>(x + 1);
+ }
+ return x;
+}
+
+// We can't suppress if there is a variadic involved.
+template<int ... D>
+int variadic_qux(int x) {
+ // Diagnoses NO_DEP 2x, once during phase 1, the second during instantiation.
+ // Dianoses DEP 3x, once per variadic expansion.
+ // expected-warning at +5 2{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ // expected-note@#NO_DEP 2{{conflicting attribute is here}}
+ // expected-warning at +3 3{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
+ // expected-note@#DEP 3{{conflicting attribute is here}}
+ // expected-note@#QUX_VARIADIC_INST{{in instantiation}}
+ [[msvc::noinline]] return non_dependent(x) + (dependent<D>(x) + ...);
+}
+
void use() {
baz<3>(0); // #BAZ_INST
variadic_baz<0, 1, 2>(0); // #VARIADIC_INST
+ qux<3>(0); // #QUX_INST
+ variadic_qux<0, 1, 2>(0); // #QUX_VARIADIC_INST
}
More information about the cfe-commits
mailing list