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@+1{{conflicting attribute is here}} +// expected-note@+1 2 {{conflicting attribute is here}} [[gnu::always_inline]] void always_inline_fn(void) { } -// expected-note@+1{{conflicting attribute is here}} +// expected-note@+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@+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@+6{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}} + // expected-note@#NO_DEP{{conflicting attribute is here}} + // expected-warning@+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@+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@+5 2{{statement attribute 'noinline' has higher precedence than function attribute 'always_inline'}} + // expected-note@#NO_DEP 2{{conflicting attribute is here}} + // expected-warning@+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 } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits