1 //===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 /// \brief This file implements parsing of all OpenMP directives and clauses.
12 //===----------------------------------------------------------------------===//
14 #include "RAIIObjectsForParser.h"
15 #include "clang/AST/ASTConsumer.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/StmtOpenMP.h"
18 #include "clang/Parse/ParseDiagnostic.h"
19 #include "clang/Parse/Parser.h"
20 #include "clang/Sema/Scope.h"
21 #include "llvm/ADT/PointerIntPair.h"
22 using namespace clang;
24 //===----------------------------------------------------------------------===//
25 // OpenMP declarative directives.
26 //===----------------------------------------------------------------------===//
28 static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
29 // Array of foldings: F[i][0] F[i][1] ===> F[i][2].
30 // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
31 // TODO: add other combined directives in topological order.
32 const OpenMPDirectiveKind F[][3] = {
33 { OMPD_for, OMPD_simd, OMPD_for_simd },
34 { OMPD_parallel, OMPD_for, OMPD_parallel_for },
35 { OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd },
36 { OMPD_parallel, OMPD_sections, OMPD_parallel_sections }
38 auto Tok = P.getCurToken();
42 : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
43 for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
44 if (DKind == F[i][0]) {
45 Tok = P.getPreprocessor().LookAhead(0);
49 : getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
50 if (SDKind == F[i][1]) {
59 /// \brief Parsing of declarative OpenMP directives.
61 /// threadprivate-directive:
62 /// annot_pragma_openmp 'threadprivate' simple-variable-list
64 Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
65 assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
66 ParenBraceBracketBalancer BalancerRAIIObj(*this);
68 SourceLocation Loc = ConsumeToken();
69 SmallVector<Expr *, 5> Identifiers;
70 auto DKind = ParseOpenMPDirectiveKind(*this);
73 case OMPD_threadprivate:
75 if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
76 // The last seen token is annot_pragma_openmp_end - need to check for
78 if (Tok.isNot(tok::annot_pragma_openmp_end)) {
79 Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
80 << getOpenMPDirectiveName(OMPD_threadprivate);
81 SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
83 // Skip the last annot_pragma_openmp_end.
85 return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
89 Diag(Tok, diag::err_omp_unknown_directive);
106 case OMPD_parallel_for:
107 case OMPD_parallel_for_simd:
108 case OMPD_parallel_sections:
112 Diag(Tok, diag::err_omp_unexpected_directive)
113 << getOpenMPDirectiveName(DKind);
116 SkipUntil(tok::annot_pragma_openmp_end);
117 return DeclGroupPtrTy();
120 /// \brief Parsing of declarative or executable OpenMP directives.
122 /// threadprivate-directive:
123 /// annot_pragma_openmp 'threadprivate' simple-variable-list
124 /// annot_pragma_openmp_end
126 /// executable-directive:
127 /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
128 /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
129 /// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
130 /// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
131 /// 'for simd' | 'parallel for simd' | 'target' | 'teams' {clause}
132 /// annot_pragma_openmp_end
135 Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
136 assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
137 ParenBraceBracketBalancer BalancerRAIIObj(*this);
138 SmallVector<Expr *, 5> Identifiers;
139 SmallVector<OMPClause *, 5> Clauses;
140 SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
141 FirstClauses(OMPC_unknown + 1);
142 unsigned ScopeFlags =
143 Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
144 SourceLocation Loc = ConsumeToken(), EndLoc;
145 auto DKind = ParseOpenMPDirectiveKind(*this);
146 // Name of critical directive.
147 DeclarationNameInfo DirName;
148 StmtResult Directive = StmtError();
149 bool HasAssociatedStatement = true;
150 bool FlushHasClause = false;
153 case OMPD_threadprivate:
155 if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
156 // The last seen token is annot_pragma_openmp_end - need to check for
158 if (Tok.isNot(tok::annot_pragma_openmp_end)) {
159 Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
160 << getOpenMPDirectiveName(OMPD_threadprivate);
161 SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
164 Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
165 Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
167 SkipUntil(tok::annot_pragma_openmp_end);
170 if (PP.LookAhead(0).is(tok::l_paren)) {
171 FlushHasClause = true;
172 // Push copy of the current token back to stream to properly parse
173 // pseudo-clause OMPFlushClause.
179 if (!StandAloneAllowed) {
180 Diag(Tok, diag::err_omp_immediate_directive)
181 << getOpenMPDirectiveName(DKind);
183 HasAssociatedStatement = false;
184 // Fall through for further analysis.
194 case OMPD_parallel_for:
195 case OMPD_parallel_for_simd:
196 case OMPD_parallel_sections:
203 // Parse directive name of the 'critical' directive if any.
204 if (DKind == OMPD_critical) {
205 BalancedDelimiterTracker T(*this, tok::l_paren,
206 tok::annot_pragma_openmp_end);
207 if (!T.consumeOpen()) {
208 if (Tok.isAnyIdentifier()) {
210 DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());
213 Diag(Tok, diag::err_omp_expected_identifier_for_critical);
219 if (isOpenMPLoopDirective(DKind))
220 ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
221 if (isOpenMPSimdDirective(DKind))
222 ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
223 ParseScope OMPDirectiveScope(this, ScopeFlags);
224 Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
226 Actions.StartOpenMPClauses();
227 while (Tok.isNot(tok::annot_pragma_openmp_end)) {
228 OpenMPClauseKind CKind =
231 : FlushHasClause ? OMPC_flush
232 : getOpenMPClauseKind(PP.getSpelling(Tok));
233 FlushHasClause = false;
235 ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
236 FirstClauses[CKind].setInt(true);
238 FirstClauses[CKind].setPointer(Clause);
239 Clauses.push_back(Clause);
243 if (Tok.is(tok::comma))
246 Actions.EndOpenMPClauses();
247 // End location of the directive.
248 EndLoc = Tok.getLocation();
249 // Consume final annot_pragma_openmp_end.
252 StmtResult AssociatedStmt;
253 bool CreateDirective = true;
254 if (HasAssociatedStatement) {
255 // The body is a block scope like in Lambdas and Blocks.
256 Sema::CompoundScopeRAII CompoundScope(Actions);
257 Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
258 Actions.ActOnStartOfCompoundStmt();
260 AssociatedStmt = ParseStatement();
261 Actions.ActOnFinishOfCompoundStmt();
262 AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
263 CreateDirective = AssociatedStmt.isUsable();
266 Directive = Actions.ActOnOpenMPExecutableDirective(
267 DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
270 Actions.EndOpenMPDSABlock(Directive.get());
271 OMPDirectiveScope.Exit();
275 Diag(Tok, diag::err_omp_unknown_directive);
276 SkipUntil(tok::annot_pragma_openmp_end);
282 /// \brief Parses list of simple variables for '#pragma omp threadprivate'
285 /// simple-variable-list:
286 /// '(' id-expression {, id-expression} ')'
288 bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
289 SmallVectorImpl<Expr *> &VarList,
290 bool AllowScopeSpecifier) {
293 BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
294 if (T.expectAndConsume(diag::err_expected_lparen_after,
295 getOpenMPDirectiveName(Kind)))
297 bool IsCorrect = true;
298 bool NoIdentIsFound = true;
300 // Read tokens while ')' or annot_pragma_openmp_end is not found.
301 while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
303 SourceLocation TemplateKWLoc;
307 NoIdentIsFound = false;
309 if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
310 ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
312 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
314 } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
315 TemplateKWLoc, Name)) {
317 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
319 } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
320 Tok.isNot(tok::annot_pragma_openmp_end)) {
322 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
324 Diag(PrevTok.getLocation(), diag::err_expected)
326 << SourceRange(PrevTok.getLocation(), PrevTokLocation);
328 DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
330 Actions.ActOnOpenMPIdExpression(getCurScope(), SS, NameInfo);
332 VarList.push_back(Res.get());
335 if (Tok.is(tok::comma)) {
340 if (NoIdentIsFound) {
341 Diag(Tok, diag::err_expected) << tok::identifier;
346 IsCorrect = !T.consumeClose() && IsCorrect;
348 return !IsCorrect && VarList.empty();
351 /// \brief Parsing of OpenMP clauses.
354 /// if-clause | final-clause | num_threads-clause | safelen-clause |
355 /// default-clause | private-clause | firstprivate-clause | shared-clause
356 /// | linear-clause | aligned-clause | collapse-clause |
357 /// lastprivate-clause | reduction-clause | proc_bind-clause |
358 /// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
359 /// mergeable-clause | flush-clause | read-clause | write-clause |
360 /// update-clause | capture-clause | seq_cst-clause
362 OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
363 OpenMPClauseKind CKind, bool FirstClause) {
364 OMPClause *Clause = nullptr;
365 bool ErrorFound = false;
366 // Check if clause is allowed for the given directive.
367 if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
368 Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
369 << getOpenMPDirectiveName(DKind);
376 case OMPC_num_threads:
379 // OpenMP [2.5, Restrictions]
380 // At most one if clause can appear on the directive.
381 // At most one num_threads clause can appear on the directive.
382 // OpenMP [2.8.1, simd construct, Restrictions]
383 // Only one safelen clause can appear on a simd directive.
384 // Only one collapse clause can appear on a simd directive.
385 // OpenMP [2.11.1, task Construct, Restrictions]
386 // At most one if clause can appear on the directive.
387 // At most one final clause can appear on the directive.
389 Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
390 << getOpenMPClauseName(CKind);
394 Clause = ParseOpenMPSingleExprClause(CKind);
398 // OpenMP [2.14.3.1, Restrictions]
399 // Only a single default clause may be specified on a parallel, task or
401 // OpenMP [2.5, parallel Construct, Restrictions]
402 // At most one proc_bind clause can appear on the directive.
404 Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
405 << getOpenMPClauseName(CKind);
409 Clause = ParseOpenMPSimpleClause(CKind);
412 // OpenMP [2.7.1, Restrictions, p. 3]
413 // Only one schedule clause can appear on a loop directive.
415 Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
416 << getOpenMPClauseName(CKind);
420 Clause = ParseOpenMPSingleExprWithArgClause(CKind);
431 // OpenMP [2.7.1, Restrictions, p. 9]
432 // Only one ordered clause can appear on a loop directive.
433 // OpenMP [2.7.1, Restrictions, C/C++, p. 4]
434 // Only one nowait clause can appear on a for directive.
436 Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind)
437 << getOpenMPClauseName(CKind);
441 Clause = ParseOpenMPClause(CKind);
444 case OMPC_firstprivate:
445 case OMPC_lastprivate:
451 case OMPC_copyprivate:
453 Clause = ParseOpenMPVarListClause(CKind);
456 Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
457 << getOpenMPDirectiveName(DKind);
458 SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
460 case OMPC_threadprivate:
461 Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
462 << getOpenMPDirectiveName(DKind);
463 SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
466 return ErrorFound ? nullptr : Clause;
469 /// \brief Parsing of OpenMP clauses with single expressions like 'if',
470 /// 'final', 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams' or
474 /// 'if' '(' expression ')'
477 /// 'final' '(' expression ')'
479 /// num_threads-clause:
480 /// 'num_threads' '(' expression ')'
483 /// 'safelen' '(' expression ')'
486 /// 'collapse' '(' expression ')'
488 OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
489 SourceLocation Loc = ConsumeToken();
491 BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
492 if (T.expectAndConsume(diag::err_expected_lparen_after,
493 getOpenMPClauseName(Kind)))
496 ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
497 ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
505 return Actions.ActOnOpenMPSingleExprClause(
506 Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
509 /// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
512 /// 'default' '(' 'none' | 'shared' ')
514 /// proc_bind-clause:
515 /// 'proc_bind' '(' 'master' | 'close' | 'spread' ')
517 OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
518 SourceLocation Loc = Tok.getLocation();
519 SourceLocation LOpen = ConsumeToken();
521 BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
522 if (T.expectAndConsume(diag::err_expected_lparen_after,
523 getOpenMPClauseName(Kind)))
526 unsigned Type = getOpenMPSimpleClauseType(
527 Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
528 SourceLocation TypeLoc = Tok.getLocation();
529 if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
530 Tok.isNot(tok::annot_pragma_openmp_end))
536 return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
540 /// \brief Parsing of OpenMP clauses like 'ordered'.
551 /// mergeable-clause:
557 OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
558 SourceLocation Loc = Tok.getLocation();
561 return Actions.ActOnOpenMPClause(Kind, Loc, Tok.getLocation());
565 /// \brief Parsing of OpenMP clauses with single expressions and some additional
566 /// argument like 'schedule' or 'dist_schedule'.
569 /// 'schedule' '(' kind [',' expression ] ')'
571 OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind) {
572 SourceLocation Loc = ConsumeToken();
573 SourceLocation CommaLoc;
575 BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
576 if (T.expectAndConsume(diag::err_expected_lparen_after,
577 getOpenMPClauseName(Kind)))
581 unsigned Type = getOpenMPSimpleClauseType(
582 Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
583 SourceLocation KLoc = Tok.getLocation();
584 if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
585 Tok.isNot(tok::annot_pragma_openmp_end))
588 if (Kind == OMPC_schedule &&
589 (Type == OMPC_SCHEDULE_static || Type == OMPC_SCHEDULE_dynamic ||
590 Type == OMPC_SCHEDULE_guided) &&
591 Tok.is(tok::comma)) {
592 CommaLoc = ConsumeAnyToken();
593 ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
594 Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional);
602 return Actions.ActOnOpenMPSingleExprWithArgClause(
603 Kind, Type, Val.get(), Loc, T.getOpenLocation(), KLoc, CommaLoc,
604 T.getCloseLocation());
607 static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
608 UnqualifiedId &ReductionId) {
609 SourceLocation TemplateKWLoc;
610 if (ReductionIdScopeSpec.isEmpty()) {
612 switch (P.getCurToken().getKind()) {
640 if (OOK != OO_None) {
641 SourceLocation OpLoc = P.ConsumeToken();
642 SourceLocation SymbolLocations[] = {OpLoc, OpLoc, SourceLocation()};
643 ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
647 return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
648 /*AllowDestructorName*/ false,
649 /*AllowConstructorName*/ false, ParsedType(),
650 TemplateKWLoc, ReductionId);
653 /// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
654 /// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
657 /// 'private' '(' list ')'
658 /// firstprivate-clause:
659 /// 'firstprivate' '(' list ')'
660 /// lastprivate-clause:
661 /// 'lastprivate' '(' list ')'
663 /// 'shared' '(' list ')'
665 /// 'linear' '(' list [ ':' linear-step ] ')'
667 /// 'aligned' '(' list [ ':' alignment ] ')'
668 /// reduction-clause:
669 /// 'reduction' '(' reduction-identifier ':' list ')'
670 /// copyprivate-clause:
671 /// 'copyprivate' '(' list ')'
673 /// 'flush' '(' list ')'
675 OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
676 SourceLocation Loc = Tok.getLocation();
677 SourceLocation LOpen = ConsumeToken();
678 SourceLocation ColonLoc = SourceLocation();
679 // Optional scope specifier and unqualified id for reduction identifier.
680 CXXScopeSpec ReductionIdScopeSpec;
681 UnqualifiedId ReductionId;
682 bool InvalidReductionId = false;
684 BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
685 if (T.expectAndConsume(diag::err_expected_lparen_after,
686 getOpenMPClauseName(Kind)))
689 // Handle reduction-identifier for reduction clause.
690 if (Kind == OMPC_reduction) {
691 ColonProtectionRAIIObject ColonRAII(*this);
692 if (getLangOpts().CPlusPlus) {
693 ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
696 ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
697 if (InvalidReductionId) {
698 SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
701 if (Tok.is(tok::colon)) {
702 ColonLoc = ConsumeToken();
704 Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
708 SmallVector<Expr *, 5> Vars;
709 bool IsComma = !InvalidReductionId;
710 const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
711 while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
712 Tok.isNot(tok::annot_pragma_openmp_end))) {
713 ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
716 Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
717 if (VarExpr.isUsable()) {
718 Vars.push_back(VarExpr.get());
720 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
724 IsComma = Tok.is(tok::comma);
727 else if (Tok.isNot(tok::r_paren) &&
728 Tok.isNot(tok::annot_pragma_openmp_end) &&
729 (!MayHaveTail || Tok.isNot(tok::colon)))
730 Diag(Tok, diag::err_omp_expected_punc)
731 << ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
732 : getOpenMPClauseName(Kind))
733 << (Kind == OMPC_flush);
736 // Parse ':' linear-step (or ':' alignment).
737 Expr *TailExpr = nullptr;
738 const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
740 ColonLoc = Tok.getLocation();
743 Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
745 TailExpr = Tail.get();
747 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
753 if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
756 return Actions.ActOnOpenMPVarListClause(
757 Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
758 ReductionIdScopeSpec,
759 ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
760 : DeclarationNameInfo());