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
clang
include/clang/Parse
lib/Parse
test/OpenMP
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue