diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 4778dc9d3df88..e7130d2fe68e7 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1153,6 +1153,7 @@ class Parser : public CodeCompletionHandler { virtual void ParseLexedMemberInitializers(); virtual void ParseLexedMethodDefs(); virtual void ParseLexedAttributes(); + virtual void ParseLexedPragmas(); }; /// Inner node of the LateParsedDeclaration tree that parses @@ -1166,6 +1167,7 @@ class Parser : public CodeCompletionHandler { void ParseLexedMemberInitializers() override; void ParseLexedMethodDefs() override; void ParseLexedAttributes() override; + void ParseLexedPragmas() override; private: Parser *Self; @@ -1195,6 +1197,26 @@ class Parser : public CodeCompletionHandler { 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 { public: @@ -1454,6 +1476,8 @@ class Parser : public CodeCompletionHandler { 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 @@ class Parser : public CodeCompletionHandler { /// 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); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index aa314da8e5b40..f8b5fec438007 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -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). diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index fe409327bfb4b..ca2497ef6121d 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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()); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index aaef4cd36d3bd..31ae3af70b714 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -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) { diff --git a/clang/test/OpenMP/declare_mapper_messages.cpp b/clang/test/OpenMP/declare_mapper_messages.cpp index 7b50fb2a52c27..bd91cdad8f40d 100644 --- a/clang/test/OpenMP/declare_mapper_messages.cpp +++ b/clang/test/OpenMP/declare_mapper_messages.cpp @@ -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; }; diff --git a/clang/test/OpenMP/declare_reduction_codegen.cpp b/clang/test/OpenMP/declare_reduction_codegen.cpp index 1f6fa2bebea36..129823c6bf6a5 100644 --- a/clang/test/OpenMP/declare_reduction_codegen.cpp +++ b/clang/test/OpenMP/declare_reduction_codegen.cpp @@ -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 d; @@ -85,6 +87,17 @@ SSS 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 void init(T &lhs, T &rhs) {} diff --git a/clang/test/OpenMP/declare_reduction_messages.cpp b/clang/test/OpenMP/declare_reduction_messages.cpp index eeafe9032e080..b1e59591d998d 100644 --- a/clang/test/OpenMP/declare_reduction_messages.cpp +++ b/clang/test/OpenMP/declare_reduction_messages.cpp @@ -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}}