Skip to content

Commit c44fa3e

Browse files
authored
[Clang] Refactor __attribute__((assume)) (#84934)
This is a followup to #81014 and #84582: Before this patch, Clang would accept `__attribute__((assume))` and `[[clang::assume]]` as nonstandard spellings for the `[[omp::assume]]` attribute; this resulted in a potentially very confusing name clash with C++23’s `[[assume]]` attribute (and GCC’s `assume` attribute with the same semantics). This pr replaces every usage of `__attribute__((assume))` with `[[omp::assume]]` and makes `__attribute__((assume))` and `[[clang::assume]]` alternative spellings for C++23’s `[[assume]]`; this shouldn’t cause any problems due to differences in appertainment and because almost no-one was using this variant spelling to begin with (a use in libclc has already been changed to use a different attribute).
1 parent 4fbc95d commit c44fa3e

26 files changed

+150
-199
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,10 +1640,11 @@ def Unlikely : StmtAttr {
16401640
def : MutualExclusions<[Likely, Unlikely]>;
16411641

16421642
def CXXAssume : StmtAttr {
1643-
let Spellings = [CXX11<"", "assume", 202207>];
1643+
let Spellings = [CXX11<"", "assume", 202207>, Clang<"assume">];
16441644
let Subjects = SubjectList<[NullStmt], ErrorDiag, "empty statements">;
16451645
let Args = [ExprArgument<"Assumption">];
16461646
let Documentation = [CXXAssumeDocs];
1647+
let HasCustomParsing = 1;
16471648
}
16481649

16491650
def NoMerge : DeclOrStmtAttr {
@@ -4255,7 +4256,7 @@ def OMPDeclareVariant : InheritableAttr {
42554256
}
42564257

42574258
def OMPAssume : InheritableAttr {
4258-
let Spellings = [Clang<"assume">, CXX11<"omp", "assume">];
4259+
let Spellings = [CXX11<"omp", "assume">];
42594260
let Subjects = SubjectList<[Function, ObjCMethod]>;
42604261
let InheritEvenIfAlreadyPresent = 1;
42614262
let Documentation = [OMPAssumeDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,9 +2027,6 @@ Different optimisers are likely to react differently to the presence of
20272027
this attribute; in some cases, adding ``assume`` may affect performance
20282028
negatively. It should be used with parsimony and care.
20292029

2030-
Note that `clang::assume` is a different attribute. Always write ``assume``
2031-
without a namespace if you intend to use the standard C++ attribute.
2032-
20332030
Example:
20342031

20352032
.. code-block:: c++
@@ -4740,7 +4737,7 @@ def OMPAssumeDocs : Documentation {
47404737
let Category = DocCatFunction;
47414738
let Heading = "assume";
47424739
let Content = [{
4743-
Clang supports the ``__attribute__((assume("assumption")))`` attribute to
4740+
Clang supports the ``[[omp::assume("assumption")]]`` attribute to
47444741
provide additional information to the optimizer. The string-literal, here
47454742
"assumption", will be attached to the function declaration such that later
47464743
analysis and optimization passes can assume the "assumption" to hold.
@@ -4752,7 +4749,7 @@ A function can have multiple assume attributes and they propagate from prior
47524749
declarations to later definitions. Multiple assumptions are aggregated into a
47534750
single comma separated string. Thus, one can provide multiple assumptions via
47544751
a comma separated string, i.a.,
4755-
``__attribute__((assume("assumption1,assumption2")))``.
4752+
``[[omp::assume("assumption1,assumption2")]]``.
47564753

47574754
While LLVM plugins might provide more assumption strings, the default LLVM
47584755
optimization passes are aware of the following assumptions:

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10237,9 +10237,6 @@ def err_fallthrough_attr_outside_switch : Error<
1023710237
def err_fallthrough_attr_invalid_placement : Error<
1023810238
"fallthrough annotation does not directly precede switch label">;
1023910239

10240-
def err_assume_attr_args : Error<
10241-
"attribute '%0' requires a single expression argument">;
10242-
1024310240
def warn_unreachable_default : Warning<
1024410241
"default label in switch which covers all enumeration values">,
1024510242
InGroup<CoveredSwitchDefault>, DefaultIgnore;

clang/include/clang/Parse/Parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2997,7 +2997,8 @@ class Parser : public CodeCompletionHandler {
29972997
bool ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
29982998
IdentifierInfo *AttrName,
29992999
SourceLocation AttrNameLoc,
3000-
SourceLocation *EndLoc);
3000+
SourceLocation *EndLoc,
3001+
ParsedAttr::Form Form);
30013002

30023003
IdentifierInfo *TryParseCXX11AttributeIdentifier(
30033004
SourceLocation &Loc,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,9 @@ void Parser::ParseGNUAttributeArgs(
666666
ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc,
667667
Form);
668668
return;
669+
} else if (AttrKind == ParsedAttr::AT_CXXAssume) {
670+
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
671+
return;
669672
}
670673

671674
// These may refer to the function arguments, but need to be parsed early to
@@ -720,6 +723,10 @@ unsigned Parser::ParseClangAttributeArgs(
720723
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
721724
ScopeName, ScopeLoc, Form);
722725
break;
726+
727+
case ParsedAttr::AT_CXXAssume:
728+
ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form);
729+
break;
723730
}
724731
return !Attrs.empty() ? Attrs.begin()->getNumArgs() : 0;
725732
}

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4560,7 +4560,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
45604560
bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
45614561
IdentifierInfo *AttrName,
45624562
SourceLocation AttrNameLoc,
4563-
SourceLocation *EndLoc) {
4563+
SourceLocation *EndLoc,
4564+
ParsedAttr::Form Form) {
45644565
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
45654566
BalancedDelimiterTracker T(*this, tok::l_paren);
45664567
T.consumeOpen();
@@ -4603,7 +4604,7 @@ bool Parser::ParseCXXAssumeAttributeArg(ParsedAttributes &Attrs,
46034604
auto RParen = Tok.getLocation();
46044605
T.consumeClose();
46054606
Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), nullptr,
4606-
SourceLocation(), &Assumption, 1, ParsedAttr::Form::CXX11());
4607+
SourceLocation(), &Assumption, 1, Form);
46074608

46084609
if (EndLoc)
46094610
*EndLoc = RParen;
@@ -4683,7 +4684,7 @@ bool Parser::ParseCXX11AttributeArgs(
46834684
ScopeName, ScopeLoc, Form);
46844685
// So does C++23's assume() attribute.
46854686
else if (!ScopeName && AttrName->isStr("assume")) {
4686-
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc))
4687+
if (ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form))
46874688
return true;
46884689
NumArgs = 1;
46894690
} else

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,8 @@ bool Sema::CheckRebuiltStmtAttributes(ArrayRef<const Attr *> Attrs) {
665665
ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
666666
SourceRange Range) {
667667
if (A.getNumArgs() != 1 || !A.getArgAsExpr(0)) {
668-
Diag(A.getLoc(), diag::err_assume_attr_args) << A.getAttrName() << Range;
668+
Diag(A.getLoc(), diag::err_attribute_wrong_number_arguments)
669+
<< A.getAttrName() << 1 << Range;
669670
return ExprError();
670671
}
671672

@@ -682,8 +683,11 @@ ExprResult Sema::ActOnCXXAssumeAttr(Stmt *St, const ParsedAttr &A,
682683
Assumption = Res.get();
683684
}
684685

685-
if (!getLangOpts().CPlusPlus23)
686+
if (!getLangOpts().CPlusPlus23 &&
687+
A.getSyntax() == AttributeCommonInfo::AS_CXX11) {
688+
llvm::dbgs() << "Syntax: " << int(A.getSyntax()) << "\n";
686689
Diag(A.getLoc(), diag::ext_cxx23_attr) << A << Range;
690+
}
687691

688692
return Assumption;
689693
}

clang/test/CodeGen/assume_attr.c

Lines changed: 0 additions & 58 deletions
This file was deleted.

clang/test/CodeGenCXX/assume_attr.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,77 +8,77 @@
88

99
/// foo: declarations only
1010

11-
__attribute__((assume("foo:before1"))) void foo();
11+
[[omp::assume("foo:before1")]] void foo();
1212

13-
__attribute__((assume("foo:before2")))
14-
__attribute__((assume("foo:before3"))) void
13+
[[omp::assume("foo:before2")]]
14+
[[omp::assume("foo:before3")]] void
1515
foo();
1616

1717
/// baz: static function declarations and a definition
1818

19-
__attribute__((assume("baz:before1"))) static void baz();
19+
[[omp::assume("baz:before1")]] static void baz();
2020

21-
__attribute__((assume("baz:before2")))
22-
__attribute__((assume("baz:before3"))) static void
21+
[[omp::assume("baz:before2")]]
22+
[[omp::assume("baz:before3")]] static void
2323
baz();
2424

2525
// Definition
26-
__attribute__((assume("baz:def1,baz:def2"))) static void baz() { foo(); }
26+
[[omp::assume("baz:def1,baz:def2")]] static void baz() { foo(); }
2727

28-
__attribute__((assume("baz:after"))) static void baz();
28+
[[omp::assume("baz:after")]] static void baz();
2929

3030
/// bar: external function declarations and a definition
3131

32-
__attribute__((assume("bar:before1"))) void bar();
32+
[[omp::assume("bar:before1")]] void bar();
3333

34-
__attribute__((assume("bar:before2")))
35-
__attribute__((assume("bar:before3"))) void
34+
[[omp::assume("bar:before2")]]
35+
[[omp::assume("bar:before3")]] void
3636
bar();
3737

3838
// Definition
39-
__attribute__((assume("bar:def1,bar:def2"))) void bar() { baz(); }
39+
[[omp::assume("bar:def1,bar:def2")]] void bar() { baz(); }
4040

41-
__attribute__((assume("bar:after"))) void bar();
41+
[[omp::assume("bar:after")]] void bar();
4242

4343
/// back to foo
4444

45-
__attribute__((assume("foo:after"))) void foo();
45+
[[omp::assume("foo:after")]] void foo();
4646

4747
/// class tests
4848
class C {
49-
__attribute__((assume("C:private_method"))) void private_method();
50-
__attribute__((assume("C:private_static"))) static void private_static();
49+
[[omp::assume("C:private_method")]] void private_method();
50+
[[omp::assume("C:private_static")]] static void private_static();
5151

5252
public:
53-
__attribute__((assume("C:public_method1"))) void public_method();
54-
__attribute__((assume("C:public_static1"))) static void public_static();
53+
[[omp::assume("C:public_method1")]] void public_method();
54+
[[omp::assume("C:public_static1")]] static void public_static();
5555
};
5656

57-
__attribute__((assume("C:public_method2"))) void C::public_method() {
57+
[[omp::assume("C:public_method2")]] void C::public_method() {
5858
private_method();
5959
}
6060

61-
__attribute__((assume("C:public_static2"))) void C::public_static() {
61+
[[omp::assume("C:public_static2")]] void C::public_static() {
6262
private_static();
6363
}
6464

6565
/// template tests
6666
template <typename T>
67-
__attribute__((assume("template_func<T>"))) void template_func() {}
67+
[[omp::assume("template_func<T>")]] void template_func() {}
6868

6969
template <>
70-
__attribute__((assume("template_func<float>"))) void template_func<float>() {}
70+
[[omp::assume("template_func<float>")]] void template_func<float>() {}
7171

7272
template <>
7373
void template_func<int>() {}
7474

7575
template <typename T>
7676
struct S {
77-
__attribute__((assume("S<T>::method"))) void method();
77+
[[omp::assume("S<T>::method")]] void method();
7878
};
7979

8080
template <>
81-
__attribute__((assume("S<float>::method"))) void S<float>::method() {}
81+
[[omp::assume("S<float>::method")]] void S<float>::method() {}
8282

8383
template <>
8484
void S<int>::method() {}

clang/test/OpenMP/assumes_codegen.cpp

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -67,46 +67,46 @@ int lambda_outer() {
6767
}
6868
#pragma omp end assumes
6969

70-
// AST: void foo() __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
71-
// AST-NEXT: }
72-
// AST-NEXT: class BAR {
73-
// AST-NEXT: public:
74-
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAR() {
75-
// AST-NEXT: }
76-
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar1() {
77-
// AST-NEXT: }
78-
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void bar2() {
79-
// AST-NEXT: }
80-
// AST-NEXT: };
81-
// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar() {
82-
// AST-NEXT: BAR b;
83-
// AST-NEXT: }
84-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz();
85-
// AST-NEXT: template <typename T> class BAZ {
86-
// AST-NEXT: public:
87-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ<T>() {
88-
// AST-NEXT: }
89-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1() {
90-
// AST-NEXT: }
91-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2() {
92-
// AST-NEXT: }
93-
// AST-NEXT: };
94-
// AST-NEXT: template<> class BAZ<float> {
95-
// AST-NEXT: public:
96-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ() {
97-
// AST-NEXT: }
98-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1();
99-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2();
100-
// AST-NEXT: };
101-
// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz() {
102-
// AST-NEXT: BAZ<float> b;
103-
// AST-NEXT: }
104-
// AST-NEXT: __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) int lambda_outer() {
105-
// AST-NEXT: auto lambda_inner = []() {
106-
// AST-NEXT: return 42;
107-
// AST-NEXT: };
108-
// AST-NEXT: return lambda_inner();
109-
// AST-NEXT: }
70+
// AST{LITERAL}: void foo() [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] {
71+
// AST-NEXT{LITERAL}: }
72+
// AST-NEXT{LITERAL}: class BAR {
73+
// AST-NEXT{LITERAL}: public:
74+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAR() {
75+
// AST-NEXT{LITERAL}: }
76+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar1() {
77+
// AST-NEXT{LITERAL}: }
78+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void bar2() {
79+
// AST-NEXT{LITERAL}: }
80+
// AST-NEXT{LITERAL}: };
81+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar() {
82+
// AST-NEXT{LITERAL}: BAR b;
83+
// AST-NEXT{LITERAL}: }
84+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz();
85+
// AST-NEXT{LITERAL}: template <typename T> class BAZ {
86+
// AST-NEXT{LITERAL}: public:
87+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ<T>() {
88+
// AST-NEXT{LITERAL}: }
89+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1() {
90+
// AST-NEXT{LITERAL}: }
91+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2() {
92+
// AST-NEXT{LITERAL}: }
93+
// AST-NEXT{LITERAL}: };
94+
// AST-NEXT{LITERAL}: template<> class BAZ<float> {
95+
// AST-NEXT{LITERAL}: public:
96+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ() {
97+
// AST-NEXT{LITERAL}: }
98+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1();
99+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2();
100+
// AST-NEXT{LITERAL}: };
101+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz() {
102+
// AST-NEXT{LITERAL}: BAZ<float> b;
103+
// AST-NEXT{LITERAL}: }
104+
// AST-NEXT{LITERAL}: [[omp::assume("ompx_lambda_assumption")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] int lambda_outer() {
105+
// AST-NEXT{LITERAL}: auto lambda_inner = []() {
106+
// AST-NEXT{LITERAL}: return 42;
107+
// AST-NEXT{LITERAL}: };
108+
// AST-NEXT{LITERAL}: return lambda_inner();
109+
// AST-NEXT{LITERAL}: }
110110

111111
#endif
112112

0 commit comments

Comments
 (0)