Skip to content

Commit 8995ccc

Browse files
authored
[Clang] Add support for [[msvc::noinline]] attribute. (#91720)
Fixes #90941. Add support for ``[[msvc::noinline]]`` attribute, which is actually an alias of ``[[clang::noinline]]``.
1 parent 6e1a042 commit 8995ccc

File tree

4 files changed

+86
-5
lines changed

4 files changed

+86
-5
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,9 +2025,12 @@ def Convergent : InheritableAttr {
20252025
def NoInline : DeclOrStmtAttr {
20262026
let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">,
20272027
CXX11<"clang", "noinline">, C23<"clang", "noinline">,
2028+
CXX11<"msvc", "noinline">, C23<"msvc", "noinline">,
20282029
Declspec<"noinline">];
2029-
let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">,
2030-
C23<"clang", "noinline">]>];
2030+
let Accessors = [Accessor<"isStmtNoInline", [CXX11<"clang", "noinline">,
2031+
C23<"clang", "noinline">,
2032+
CXX11<"msvc", "noinline">,
2033+
C23<"msvc", "noinline">]>];
20312034
let Documentation = [NoInlineDocs];
20322035
let Subjects = SubjectList<[Function, Stmt], WarnDiag,
20332036
"functions and statements">;

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ bool Sema::CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
285285
static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
286286
SourceRange Range) {
287287
NoInlineAttr NIA(S.Context, A);
288-
if (!NIA.isClangNoInline()) {
288+
if (!NIA.isStmtNoInline()) {
289289
S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
290290
<< "[[clang::noinline]]";
291291
return nullptr;

clang/test/CodeGen/attr-noinline.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ static int baz(int x) {
99
}
1010

1111
[[clang::noinline]] bool noi() { }
12+
[[msvc::noinline]] bool ms_noi() { return true; }
1213

1314
void foo(int i) {
1415
[[clang::noinline]] bar();
@@ -39,6 +40,31 @@ void foo(int i) {
3940
// CHECK: call noundef zeroext i1 @_Z3barv()
4041
}
4142

43+
void ms_noi_check(int i) {
44+
[[msvc::noinline]] bar();
45+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR:[0-9]+]]
46+
[[msvc::noinline]] i = baz(i);
47+
// CHECK: call noundef i32 @_ZL3bazi({{.*}}) #[[NOINLINEATTR]]
48+
[[msvc::noinline]] (i = 4, bar());
49+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
50+
[[msvc::noinline]] (void)(bar());
51+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
52+
[[msvc::noinline]] f(bar(), bar());
53+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
54+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
55+
// CHECK: call void @_Z1fbb({{.*}}) #[[NOINLINEATTR]]
56+
[[msvc::noinline]] [] { bar(); bar(); }(); // noinline only applies to the anonymous function call
57+
// CHECK: call void @"_ZZ12ms_noi_checkiENK3$_0clEv"(ptr {{[^,]*}} %ref.tmp) #[[NOINLINEATTR]]
58+
[[msvc::noinline]] for (bar(); bar(); bar()) {}
59+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
60+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
61+
// CHECK: call noundef zeroext i1 @_Z3barv() #[[NOINLINEATTR]]
62+
[[msvc::noinline]] ms_noi();
63+
// CHECK: call noundef zeroext i1 @_Z6ms_noiv()
64+
ms_noi();
65+
// CHECK: call noundef zeroext i1 @_Z6ms_noiv()
66+
}
67+
4268
struct S {
4369
friend bool operator==(const S &LHS, const S &RHS);
4470
};
@@ -50,6 +76,12 @@ void func(const S &s1, const S &s2) {
5076
bool b;
5177
[[clang::noinline]] b = s1 == s2;
5278
// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
79+
80+
[[msvc::noinline]]g(s1 == s2);
81+
// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
82+
// CHECK: call void @_Z1gb({{.*}}) #[[NOINLINEATTR]]
83+
[[msvc::noinline]] b = s1 == s2;
84+
// CHECK: call noundef zeroext i1 @_ZeqRK1SS1_({{.*}}) #[[NOINLINEATTR]]
5385
}
5486

5587
// CHECK: attributes #[[NOINLINEATTR]] = { noinline }

clang/test/Sema/attr-noinline.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
int bar();
44

5-
// expected-note@+1{{conflicting attribute is here}}
5+
// expected-note@+1 2 {{conflicting attribute is here}}
66
[[gnu::always_inline]] void always_inline_fn(void) { }
7-
// expected-note@+1{{conflicting attribute is here}}
7+
// expected-note@+1 2 {{conflicting attribute is here}}
88
[[gnu::flatten]] void flatten_fn(void) { }
99
[[gnu::noinline]] void noinline_fn(void) { }
1010

@@ -25,7 +25,21 @@ void foo() {
2525
__attribute__((noinline)) bar(); // expected-warning {{attribute is ignored on this statement as it only applies to functions; use '[[clang::noinline]]' on statements}}
2626
}
2727

28+
void ms_noi_check() {
29+
[[msvc::noinline]] bar();
30+
[[msvc::noinline(0)]] bar(); // expected-error {{'noinline' attribute takes no arguments}}
31+
int x;
32+
[[msvc::noinline]] x = 0; // expected-warning {{'noinline' attribute is ignored because there exists no call expression inside the statement}}
33+
[[msvc::noinline]] { asm("nop"); } // expected-warning {{'noinline' attribute is ignored because there exists no call expression inside the statement}}
34+
[[msvc::noinline]] label: x = 1; // expected-warning {{'noinline' attribute only applies to functions and statements}}
35+
36+
[[msvc::noinline]] always_inline_fn(); // expected-warning {{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
37+
[[msvc::noinline]] flatten_fn(); // expected-warning {{statement attribute 'noinline' has higher precedence than function attribute 'flatten'}}
38+
[[msvc::noinline]] noinline_fn();
39+
}
40+
2841
[[clang::noinline]] static int i = bar(); // expected-warning {{'noinline' attribute only applies to functions and statements}}
42+
[[msvc::noinline]] static int j = bar(); // expected-warning {{'noinline' attribute only applies to functions and statements}}
2943

3044
// This used to crash the compiler.
3145
template<int D>
@@ -69,7 +83,39 @@ int variadic_baz(int x) {
6983
[[clang::noinline]] return non_dependent(x) + (dependent<D>(x) + ...);
7084
}
7185

86+
template<int D> [[clang::always_inline]]
87+
int qux(int x) { // #QUX
88+
// expected-warning@+2{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
89+
// expected-note@#NO_DEP{{conflicting attribute is here}}
90+
[[msvc::noinline]] non_dependent(x);
91+
if constexpr (D>0) {
92+
// expected-warning@+6{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
93+
// expected-note@#NO_DEP{{conflicting attribute is here}}
94+
// expected-warning@+4 3{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
95+
// expected-note@#QUX 3{{conflicting attribute is here}}
96+
// expected-note@#QUX_INST 3{{in instantiation}}
97+
// expected-note@+1 3{{in instantiation}}
98+
[[msvc::noinline]] return non_dependent(x), qux<D-1>(x + 1);
99+
}
100+
return x;
101+
}
102+
103+
// We can't suppress if there is a variadic involved.
104+
template<int ... D>
105+
int variadic_qux(int x) {
106+
// Diagnoses NO_DEP 2x, once during phase 1, the second during instantiation.
107+
// Dianoses DEP 3x, once per variadic expansion.
108+
// expected-warning@+5 2{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
109+
// expected-note@#NO_DEP 2{{conflicting attribute is here}}
110+
// expected-warning@+3 3{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}}
111+
// expected-note@#DEP 3{{conflicting attribute is here}}
112+
// expected-note@#QUX_VARIADIC_INST{{in instantiation}}
113+
[[msvc::noinline]] return non_dependent(x) + (dependent<D>(x) + ...);
114+
}
115+
72116
void use() {
73117
baz<3>(0); // #BAZ_INST
74118
variadic_baz<0, 1, 2>(0); // #VARIADIC_INST
119+
qux<3>(0); // #QUX_INST
120+
variadic_qux<0, 1, 2>(0); // #QUX_VARIADIC_INST
75121
}

0 commit comments

Comments
 (0)