[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.
This commit is contained in:
Alexey Bataev 2020-01-07 13:39:18 -05:00
parent 16f47cf607
commit c972f6fd79
7 changed files with 127 additions and 9 deletions

View File

@ -1153,6 +1153,7 @@ private:
virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
virtual void ParseLexedAttributes();
virtual void ParseLexedPragmas();
};
/// Inner node of the LateParsedDeclaration tree that parses
@ -1166,6 +1167,7 @@ private:
void ParseLexedMemberInitializers() override;
void ParseLexedMethodDefs() override;
void ParseLexedAttributes() override;
void ParseLexedPragmas() override;
private:
Parser *Self;
@ -1195,6 +1197,26 @@ private:
void addDecl(Decl *D) { Decls.push_back(D); }
};
/// Contains the lexed tokens of a pragma with arguments that
/// may reference member variables and so need to be parsed at the
/// end of the class declaration after parsing all other member
/// member declarations.
class LateParsedPragma : public LateParsedDeclaration {
Parser *Self = nullptr;
AccessSpecifier AS = AS_none;
CachedTokens Toks;
public:
explicit LateParsedPragma(Parser *P, AccessSpecifier AS)
: Self(P), AS(AS) {}
void takeToks(CachedTokens &Cached) { Toks.swap(Cached); }
const CachedTokens &toks() const { return Toks; }
AccessSpecifier getAccessSpecifier() const { return AS; }
void ParseLexedPragmas() override;
};
// A list of late-parsed attributes. Used by ParseGNUAttributes.
class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
public:
@ -1454,6 +1476,8 @@ private:
void ParseLexedMemberInitializers(ParsingClass &Class);
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
void ParseLexedPragmas(ParsingClass &Class);
void ParseLexedPragma(LateParsedPragma &LP);
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK);
bool ConsumeAndStoreConditional(CachedTokens &Toks);
@ -2875,7 +2899,7 @@ private:
/// Parses declarative OpenMP directives.
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
DeclSpec::TST TagType = DeclSpec::TST_unspecified,
bool Delayed = false, DeclSpec::TST TagType = DeclSpec::TST_unspecified,
Decl *TagDecl = nullptr);
/// Parse 'omp declare reduction' construct.
DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);

View File

@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
void Parser::LateParsedDeclaration::ParseLexedPragmas() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
: Self(P), Class(C) {}
@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() {
Self->ParseLexedMethodDefs(*Class);
}
void Parser::LateParsedClass::ParseLexedPragmas() {
Self->ParseLexedPragmas(*Class);
}
void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
Self->ParseLexedMethodDeclaration(*this);
}
@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
Self->ParseLexedMemberInitializer(*this);
}
void Parser::LateParsedPragma::ParseLexedPragmas() {
Self->ParseLexedPragma(*this);
}
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
ConsumeAnyToken();
}
void Parser::ParseLexedPragmas(ParsingClass &Class) {
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
HasTemplateScope);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
if (HasTemplateScope) {
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
++CurTemplateDepthTracker;
}
bool HasClassScope = !Class.TopLevelClass;
ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope,
HasClassScope);
for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations)
LPD->ParseLexedPragmas();
}
void Parser::ParseLexedPragma(LateParsedPragma &LP) {
PP.EnterToken(Tok, /*IsReinject=*/true);
PP.EnterTokenStream(LP.toks(), /*DisableMacroExpansion=*/true,
/*IsReinject=*/true);
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert(Tok.isAnnotation() && "Expected annotation token.");
switch (Tok.getKind()) {
case tok::annot_pragma_openmp: {
AccessSpecifier AS = LP.getAccessSpecifier();
ParsedAttributesWithRange Attrs(AttrFactory);
(void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs);
break;
}
default:
llvm_unreachable("Unexpected token.");
}
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
/// container until the token 'T' is reached (which gets
/// consumed/stored too, if ConsumeFinalToken).

View File

@ -3136,8 +3136,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
}
case tok::annot_pragma_openmp:
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
TagDecl);
return ParseOpenMPDeclarativeDirectiveWithExtDecl(
AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
default:
if (tok::isPragmaAnnotation(Tok.getKind())) {
@ -3355,6 +3355,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// declarations and the lexed inline method definitions, along with any
// delayed attributes.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedPragmas(getCurrentClass());
ParseLexedAttributes(getCurrentClass());
ParseLexedMethodDeclarations(getCurrentClass());

View File

@ -1336,14 +1336,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
/// annot_pragma_openmp_end
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
DeclSpec::TST TagType, Decl *Tag) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParsingOpenMPDirectiveRAII DirScope(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SourceLocation Loc = ConsumeAnnotationToken();
OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);
SourceLocation Loc;
OpenMPDirectiveKind DKind;
if (Delayed) {
TentativeParsingAction TPA(*this);
Loc = ConsumeAnnotationToken();
DKind = parseOpenMPDirectiveKind(*this);
if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) {
// Need to delay parsing until completion of the parent class.
TPA.Revert();
CachedTokens Toks;
unsigned Cnt = 1;
Toks.push_back(Tok);
while (Cnt && Tok.isNot(tok::eof)) {
(void)ConsumeAnyToken();
if (Tok.is(tok::annot_pragma_openmp))
++Cnt;
else if (Tok.is(tok::annot_pragma_openmp_end))
--Cnt;
Toks.push_back(Tok);
}
// Skip last annot_pragma_openmp_end.
if (Cnt == 0)
(void)ConsumeAnyToken();
auto *LP = new LateParsedPragma(this, AS);
LP->takeToks(Toks);
getCurrentClass().LateParsedDeclarations.push_back(LP);
return nullptr;
}
TPA.Commit();
} else {
Loc = ConsumeAnnotationToken();
DKind = parseOpenMPDirectiveKind(*this);
}
switch (DKind) {
case OMPD_threadprivate: {
@ -1495,7 +1526,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
DeclGroupPtrTy Ptr;
if (Tok.is(tok::annot_pragma_openmp)) {
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag);
Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed,
TagType, Tag);
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// Here we expect to see some function declaration.
if (AS == AS_none) {

View File

@ -8,12 +8,12 @@
int temp; // expected-note {{'temp' declared here}}
class vec { // expected-note {{definition of 'vec' is not complete until the closing '}'}}
class vec {
private:
int p; // expected-note {{declared private here}}
public:
int len;
#pragma omp declare mapper(id: vec v) map(v.len) // expected-error {{member access into incomplete type 'vec'}}
#pragma omp declare mapper(id: vec v) map(v.len)
double *data;
};

View File

@ -69,6 +69,8 @@ struct SSS {
T a;
SSS() : a() {}
#pragma omp declare reduction(fun : T : omp_out ^= omp_in) initializer(omp_priv = 24 + omp_orig)
#pragma omp declare reduction(sssss : T : ssssss(omp_in)) initializer(omp_priv = 18 + omp_orig)
static void ssssss(T &x);
};
SSS<int> d;
@ -85,6 +87,17 @@ SSS<int> d;
// CHECK-NEXT: ret void
// CHECK-NEXT: }
// CHECK: define internal {{.*}}void @{{[^(]+}}(i32* noalias %0, i32* noalias %1)
// CHECK: call void @_ZN3SSSIiE6ssssssERi(i32* dereferenceable{{.*}})
// CHECK-NEXT: ret void
// CHECK-NEXT: }
// CHECK: define internal {{.*}}void @{{[^(]+}}(i32* noalias %0, i32* noalias %1)
// CHECK: [[ADD:%.+]] = add nsw i32 18,
// CHECK-NEXT: store i32 [[ADD]], i32*
// CHECK-NEXT: ret void
// CHECK-NEXT: }
template <typename T>
void init(T &lhs, T &rhs) {}

View File

@ -166,6 +166,8 @@ struct S
void foo(S &x) {};
// expected-error@+1 {{too many arguments to function call, expected single argument 'x', have 2 arguments}}
#pragma omp declare reduction (foo : U, S : omp_out.foo(omp_in, false))
#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'}}
static void bar(S &x); // expected-note {{passing argument to parameter 'x' here}}
};
// expected-warning@+2 {{extra tokens at the end of '#pragma omp declare reduction' are ignored}}
// expected-note@+1 {{in instantiation of template class 'S<1>' requested here}}