forked from OSchip/llvm-project
[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:
parent
16f47cf607
commit
c972f6fd79
|
@ -1153,6 +1153,7 @@ private:
|
||||||
virtual void ParseLexedMemberInitializers();
|
virtual void ParseLexedMemberInitializers();
|
||||||
virtual void ParseLexedMethodDefs();
|
virtual void ParseLexedMethodDefs();
|
||||||
virtual void ParseLexedAttributes();
|
virtual void ParseLexedAttributes();
|
||||||
|
virtual void ParseLexedPragmas();
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Inner node of the LateParsedDeclaration tree that parses
|
/// Inner node of the LateParsedDeclaration tree that parses
|
||||||
|
@ -1166,6 +1167,7 @@ private:
|
||||||
void ParseLexedMemberInitializers() override;
|
void ParseLexedMemberInitializers() override;
|
||||||
void ParseLexedMethodDefs() override;
|
void ParseLexedMethodDefs() override;
|
||||||
void ParseLexedAttributes() override;
|
void ParseLexedAttributes() override;
|
||||||
|
void ParseLexedPragmas() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Parser *Self;
|
Parser *Self;
|
||||||
|
@ -1195,6 +1197,26 @@ private:
|
||||||
void addDecl(Decl *D) { Decls.push_back(D); }
|
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.
|
// A list of late-parsed attributes. Used by ParseGNUAttributes.
|
||||||
class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
|
class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
|
||||||
public:
|
public:
|
||||||
|
@ -1454,6 +1476,8 @@ private:
|
||||||
void ParseLexedMemberInitializers(ParsingClass &Class);
|
void ParseLexedMemberInitializers(ParsingClass &Class);
|
||||||
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
|
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
|
||||||
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
|
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
|
||||||
|
void ParseLexedPragmas(ParsingClass &Class);
|
||||||
|
void ParseLexedPragma(LateParsedPragma &LP);
|
||||||
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
|
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
|
||||||
bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK);
|
bool ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK);
|
||||||
bool ConsumeAndStoreConditional(CachedTokens &Toks);
|
bool ConsumeAndStoreConditional(CachedTokens &Toks);
|
||||||
|
@ -2875,7 +2899,7 @@ private:
|
||||||
/// Parses declarative OpenMP directives.
|
/// Parses declarative OpenMP directives.
|
||||||
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
|
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
|
||||||
DeclSpec::TST TagType = DeclSpec::TST_unspecified,
|
bool Delayed = false, DeclSpec::TST TagType = DeclSpec::TST_unspecified,
|
||||||
Decl *TagDecl = nullptr);
|
Decl *TagDecl = nullptr);
|
||||||
/// Parse 'omp declare reduction' construct.
|
/// Parse 'omp declare reduction' construct.
|
||||||
DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);
|
DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);
|
||||||
|
|
|
@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
|
||||||
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
|
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
|
||||||
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
|
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
|
||||||
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
|
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
|
||||||
|
void Parser::LateParsedDeclaration::ParseLexedPragmas() {}
|
||||||
|
|
||||||
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
|
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
|
||||||
: Self(P), Class(C) {}
|
: Self(P), Class(C) {}
|
||||||
|
@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() {
|
||||||
Self->ParseLexedMethodDefs(*Class);
|
Self->ParseLexedMethodDefs(*Class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::LateParsedClass::ParseLexedPragmas() {
|
||||||
|
Self->ParseLexedPragmas(*Class);
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
|
void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
|
||||||
Self->ParseLexedMethodDeclaration(*this);
|
Self->ParseLexedMethodDeclaration(*this);
|
||||||
}
|
}
|
||||||
|
@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
|
||||||
Self->ParseLexedMemberInitializer(*this);
|
Self->ParseLexedMemberInitializer(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::LateParsedPragma::ParseLexedPragmas() {
|
||||||
|
Self->ParseLexedPragma(*this);
|
||||||
|
}
|
||||||
|
|
||||||
/// ParseLexedMethodDeclarations - We finished parsing the member
|
/// ParseLexedMethodDeclarations - We finished parsing the member
|
||||||
/// specification of a top (non-nested) C++ class. Now go over the
|
/// specification of a top (non-nested) C++ class. Now go over the
|
||||||
/// stack of method declarations with some parts for which parsing was
|
/// stack of method declarations with some parts for which parsing was
|
||||||
|
@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
|
||||||
ConsumeAnyToken();
|
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
|
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
|
||||||
/// container until the token 'T' is reached (which gets
|
/// container until the token 'T' is reached (which gets
|
||||||
/// consumed/stored too, if ConsumeFinalToken).
|
/// consumed/stored too, if ConsumeFinalToken).
|
||||||
|
|
|
@ -3136,8 +3136,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
|
||||||
}
|
}
|
||||||
|
|
||||||
case tok::annot_pragma_openmp:
|
case tok::annot_pragma_openmp:
|
||||||
return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType,
|
return ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
TagDecl);
|
AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (tok::isPragmaAnnotation(Tok.getKind())) {
|
if (tok::isPragmaAnnotation(Tok.getKind())) {
|
||||||
|
@ -3355,6 +3355,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||||
// declarations and the lexed inline method definitions, along with any
|
// declarations and the lexed inline method definitions, along with any
|
||||||
// delayed attributes.
|
// delayed attributes.
|
||||||
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
||||||
|
ParseLexedPragmas(getCurrentClass());
|
||||||
ParseLexedAttributes(getCurrentClass());
|
ParseLexedAttributes(getCurrentClass());
|
||||||
ParseLexedMethodDeclarations(getCurrentClass());
|
ParseLexedMethodDeclarations(getCurrentClass());
|
||||||
|
|
||||||
|
|
|
@ -1336,14 +1336,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind,
|
||||||
/// annot_pragma_openmp_end
|
/// annot_pragma_openmp_end
|
||||||
///
|
///
|
||||||
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
|
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed,
|
||||||
DeclSpec::TST TagType, Decl *Tag) {
|
DeclSpec::TST TagType, Decl *Tag) {
|
||||||
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
|
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
|
||||||
ParsingOpenMPDirectiveRAII DirScope(*this);
|
ParsingOpenMPDirectiveRAII DirScope(*this);
|
||||||
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
||||||
|
|
||||||
SourceLocation Loc = ConsumeAnnotationToken();
|
SourceLocation Loc;
|
||||||
OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this);
|
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) {
|
switch (DKind) {
|
||||||
case OMPD_threadprivate: {
|
case OMPD_threadprivate: {
|
||||||
|
@ -1495,7 +1526,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
|
|
||||||
DeclGroupPtrTy Ptr;
|
DeclGroupPtrTy Ptr;
|
||||||
if (Tok.is(tok::annot_pragma_openmp)) {
|
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()) {
|
} else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
|
||||||
// Here we expect to see some function declaration.
|
// Here we expect to see some function declaration.
|
||||||
if (AS == AS_none) {
|
if (AS == AS_none) {
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
int temp; // expected-note {{'temp' declared here}}
|
int temp; // expected-note {{'temp' declared here}}
|
||||||
|
|
||||||
class vec { // expected-note {{definition of 'vec' is not complete until the closing '}'}}
|
class vec {
|
||||||
private:
|
private:
|
||||||
int p; // expected-note {{declared private here}}
|
int p; // expected-note {{declared private here}}
|
||||||
public:
|
public:
|
||||||
int len;
|
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;
|
double *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,8 @@ struct SSS {
|
||||||
T a;
|
T a;
|
||||||
SSS() : a() {}
|
SSS() : a() {}
|
||||||
#pragma omp declare reduction(fun : T : omp_out ^= omp_in) initializer(omp_priv = 24 + omp_orig)
|
#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;
|
SSS<int> d;
|
||||||
|
@ -85,6 +87,17 @@ SSS<int> d;
|
||||||
// CHECK-NEXT: ret void
|
// CHECK-NEXT: ret void
|
||||||
// CHECK-NEXT: }
|
// 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>
|
template <typename T>
|
||||||
void init(T &lhs, T &rhs) {}
|
void init(T &lhs, T &rhs) {}
|
||||||
|
|
||||||
|
|
|
@ -166,6 +166,8 @@ struct S
|
||||||
void foo(S &x) {};
|
void foo(S &x) {};
|
||||||
// expected-error@+1 {{too many arguments to function call, expected single argument 'x', have 2 arguments}}
|
// 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 (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-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}}
|
// expected-note@+1 {{in instantiation of template class 'S<1>' requested here}}
|
||||||
|
|
Loading…
Reference in New Issue