Skip to content

Commit c972f6f

Browse files
committed
[OPENMP]Allow using of members in standalone declaration pragmas.
If standalone OpenMP declaration pragma, like declare mapper or declare reduction, is declared in the class context, it may reference a member (data or function) in its internal expressions/statements. So, the parsing of such pragmas must be dalayed just like the parsing of the member initializers/definitions before the completion of the class declaration.
1 parent 16f47cf commit c972f6f

File tree

7 files changed

+127
-9
lines changed

7 files changed

+127
-9
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,7 @@ class Parser : public CodeCompletionHandler {
11531153
virtual void ParseLexedMemberInitializers();
11541154
virtual void ParseLexedMethodDefs();
11551155
virtual void ParseLexedAttributes();
1156+
virtual void ParseLexedPragmas();
11561157
};
11571158

11581159
/// Inner node of the LateParsedDeclaration tree that parses
@@ -1166,6 +1167,7 @@ class Parser : public CodeCompletionHandler {
11661167
void ParseLexedMemberInitializers() override;
11671168
void ParseLexedMethodDefs() override;
11681169
void ParseLexedAttributes() override;
1170+
void ParseLexedPragmas() override;
11691171

11701172
private:
11711173
Parser *Self;
@@ -1195,6 +1197,26 @@ class Parser : public CodeCompletionHandler {
11951197
void addDecl(Decl *D) { Decls.push_back(D); }
11961198
};
11971199

1200+
/// Contains the lexed tokens of a pragma with arguments that
1201+
/// may reference member variables and so need to be parsed at the
1202+
/// end of the class declaration after parsing all other member
1203+
/// member declarations.
1204+
class LateParsedPragma : public LateParsedDeclaration {
1205+
Parser *Self = nullptr;
1206+
AccessSpecifier AS = AS_none;
1207+
CachedTokens Toks;
1208+
1209+
public:
1210+
explicit LateParsedPragma(Parser *P, AccessSpecifier AS)
1211+
: Self(P), AS(AS) {}
1212+
1213+
void takeToks(CachedTokens &Cached) { Toks.swap(Cached); }
1214+
const CachedTokens &toks() const { return Toks; }
1215+
AccessSpecifier getAccessSpecifier() const { return AS; }
1216+
1217+
void ParseLexedPragmas() override;
1218+
};
1219+
11981220
// A list of late-parsed attributes. Used by ParseGNUAttributes.
11991221
class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
12001222
public:
@@ -1454,6 +1476,8 @@ class Parser : public CodeCompletionHandler {
14541476
void ParseLexedMemberInitializers(ParsingClass &Class);
14551477
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
14561478
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
1479+
void ParseLexedPragmas(ParsingClass &Class);
1480+
void ParseLexedPragma(LateParsedPragma &LP);
14571481
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
14581482
bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK);
14591483
bool ConsumeAndStoreConditional(CachedTokens &Toks);
@@ -2875,7 +2899,7 @@ class Parser : public CodeCompletionHandler {
28752899
/// Parses declarative OpenMP directives.
28762900
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
28772901
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
2878-
DeclSpec::TST TagType = DeclSpec::TST_unspecified,
2902+
bool Delayed = false, DeclSpec::TST TagType = DeclSpec::TST_unspecified,
28792903
Decl *TagDecl = nullptr);
28802904
/// Parse 'omp declare reduction' construct.
28812905
DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);

clang/lib/Parse/ParseCXXInlineMethods.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
223223
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
224224
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
225225
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
226+
void Parser::LateParsedDeclaration::ParseLexedPragmas() {}
226227

227228
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
228229
: Self(P), Class(C) {}
@@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() {
243244
Self->ParseLexedMethodDefs(*Class);
244245
}
245246

247+
void Parser::LateParsedClass::ParseLexedPragmas() {
248+
Self->ParseLexedPragmas(*Class);
249+
}
250+
246251
void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
247252
Self->ParseLexedMethodDeclaration(*this);
248253
}
@@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
255260
Self->ParseLexedMemberInitializer(*this);
256261
}
257262

263+
void Parser::LateParsedPragma::ParseLexedPragmas() {
264+
Self->ParseLexedPragma(*this);
265+
}
266+
258267
/// ParseLexedMethodDeclarations - We finished parsing the member
259268
/// specification of a top (non-nested) C++ class. Now go over the
260269
/// stack of method declarations with some parts for which parsing was
@@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
651660
ConsumeAnyToken();
652661
}
653662

663+
void Parser::ParseLexedPragmas(ParsingClass &Class) {
664+
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
665+
ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
666+
HasTemplateScope);
667+
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
668+
if (HasTemplateScope) {
669+
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
670+
++CurTemplateDepthTracker;
671+
}
672+
bool HasClassScope = !Class.TopLevelClass;
673+
ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope,
674+
HasClassScope);
675+
676+
for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations)
677+
LPD->ParseLexedPragmas();
678+
}
679+
680+
void Parser::ParseLexedPragma(LateParsedPragma &LP) {
681+
PP.EnterToken(Tok, /*IsReinject=*/true);
682+
PP.EnterTokenStream(LP.toks(), /*DisableMacroExpansion=*/true,
683+
/*IsReinject=*/true);
684+
685+
// Consume the previously pushed token.
686+
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
687+
assert(Tok.isAnnotation() && "Expected annotation token.");
688+
switch (Tok.getKind()) {
689+
case tok::annot_pragma_openmp: {
690+
AccessSpecifier AS = LP.getAccessSpecifier();
691+
ParsedAttributesWithRange Attrs(AttrFactory);
692+
(void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
693+
break;
694+
}
695+
default:
696+
llvm_unreachable("Unexpected token.");
697+
}
698+
}
699+
654700
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
655701
/// container until the token 'T' is reached (which gets
656702
/// consumed/stored too, if ConsumeFinalToken).

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3136,8 +3136,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
31363136
}
31373137

31383138
case tok::annot_pragma_openmp:
3139-
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
3140-
TagDecl);
3139+
return ParseOpenMPDeclarativeDirectiveWithExtDecl(
3140+
AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
31413141

31423142
default:
31433143
if (tok::isPragmaAnnotation(Tok.getKind())) {
@@ -3355,6 +3355,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
33553355
// declarations and the lexed inline method definitions, along with any
33563356
// delayed attributes.
33573357
SourceLocation SavedPrevTokLocation = PrevTokLocation;
3358+
ParseLexedPragmas(getCurrentClass());
33583359
ParseLexedAttributes(getCurrentClass());
33593360
ParseLexedMethodDeclarations(getCurrentClass());
33603361

clang/lib/Parse/ParseOpenMP.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,14 +1336,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
13361336
/// annot_pragma_openmp_end
13371337
///
13381338
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
1339-
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
1339+
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
13401340
DeclSpec::TST TagType, Decl *Tag) {
13411341
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
13421342
ParsingOpenMPDirectiveRAII DirScope(*this);
13431343
ParenBraceBracketBalancer BalancerRAIIObj(*this);
13441344

1345-
SourceLocation Loc = ConsumeAnnotationToken();
1346-
OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);
1345+
SourceLocation Loc;
1346+
OpenMPDirectiveKind DKind;
1347+
if (Delayed) {
1348+
TentativeParsingAction TPA(*this);
1349+
Loc = ConsumeAnnotationToken();
1350+
DKind = parseOpenMPDirectiveKind(*this);
1351+
if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {
1352+
// Need to delay parsing until completion of the parent class.
1353+
TPA.Revert();
1354+
CachedTokens Toks;
1355+
unsigned Cnt = 1;
1356+
Toks.push_back(Tok);
1357+
while (Cnt && Tok.isNot(tok::eof)) {
1358+
(void)ConsumeAnyToken();
1359+
if (Tok.is(tok::annot_pragma_openmp))
1360+
++Cnt;
1361+
else if (Tok.is(tok::annot_pragma_openmp_end))
1362+
--Cnt;
1363+
Toks.push_back(Tok);
1364+
}
1365+
// Skip last annot_pragma_openmp_end.
1366+
if (Cnt == 0)
1367+
(void)ConsumeAnyToken();
1368+
auto *LP = new LateParsedPragma(this, AS);
1369+
LP->takeToks(Toks);
1370+
getCurrentClass().LateParsedDeclarations.push_back(LP);
1371+
return nullptr;
1372+
}
1373+
TPA.Commit();
1374+
} else {
1375+
Loc = ConsumeAnnotationToken();
1376+
DKind = parseOpenMPDirectiveKind(*this);
1377+
}
13471378

13481379
switch (DKind) {
13491380
case OMPD_threadprivate: {
@@ -1495,7 +1526,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
14951526

14961527
DeclGroupPtrTy Ptr;
14971528
if (Tok.is(tok::annot_pragma_openmp)) {
1498-
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag);
1529+
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
1530+
TagType, Tag);
14991531
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
15001532
// Here we expect to see some function declaration.
15011533
if (AS == AS_none) {

clang/test/OpenMP/declare_mapper_messages.cpp

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

99
int temp; // expected-note {{'temp' declared here}}
1010

11-
class vec { // expected-note {{definition of 'vec' is not complete until the closing '}'}}
11+
class vec {
1212
private:
1313
int p; // expected-note {{declared private here}}
1414
public:
1515
int len;
16-
#pragma omp declare mapper(id: vec v) map(v.len) // expected-error {{member access into incomplete type 'vec'}}
16+
#pragma omp declare mapper(id: vec v) map(v.len)
1717
double *data;
1818
};
1919

clang/test/OpenMP/declare_reduction_codegen.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ struct SSS {
6969
T a;
7070
SSS() : a() {}
7171
#pragma omp declare reduction(fun : T : omp_out ^= omp_in) initializer(omp_priv = 24 + omp_orig)
72+
#pragma omp declare reduction(sssss : T : ssssss(omp_in)) initializer(omp_priv = 18 + omp_orig)
73+
static void ssssss(T &x);
7274
};
7375

7476
SSS<int> d;
@@ -85,6 +87,17 @@ SSS<int> d;
8587
// CHECK-NEXT: ret void
8688
// CHECK-NEXT: }
8789

90+
// CHECK: define internal {{.*}}void @{{[^(]+}}(i32* noalias %0, i32* noalias %1)
91+
// CHECK: call void @_ZN3SSSIiE6ssssssERi(i32* dereferenceable{{.*}})
92+
// CHECK-NEXT: ret void
93+
// CHECK-NEXT: }
94+
95+
// CHECK: define internal {{.*}}void @{{[^(]+}}(i32* noalias %0, i32* noalias %1)
96+
// CHECK: [[ADD:%.+]] = add nsw i32 18,
97+
// CHECK-NEXT: store i32 [[ADD]], i32*
98+
// CHECK-NEXT: ret void
99+
// CHECK-NEXT: }
100+
88101
template <typename T>
89102
void init(T &lhs, T &rhs) {}
90103

clang/test/OpenMP/declare_reduction_messages.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ struct S
166166
void foo(S &x) {};
167167
// expected-error@+1 {{too many arguments to function call, expected single argument 'x', have 2 arguments}}
168168
#pragma omp declare reduction (foo : U, S : omp_out.foo(omp_in, false))
169+
#pragma omp declare reduction (xxx : U, S : bar(omp_in)) // expected-error {{non-const lvalue reference to type 'S<1>' cannot bind to a value of unrelated type 'U'}}
170+
static void bar(S &x); // expected-note {{passing argument to parameter 'x' here}}
169171
};
170172
// expected-warning@+2 {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
171173
// expected-note@+1 {{in instantiation of template class 'S<1>' requested here}}

0 commit comments

Comments
 (0)