@@ -275,18 +275,21 @@ struct SpecificModifierParser {
275275
276276// --- Iterator helpers -----------------------------------------------
277277
278+ static EntityDecl MakeEntityDecl(ObjectName &&name) {
279+ return EntityDecl(
280+ /*ObjectName=*/std::move(name), std::optional<ArraySpec>{},
281+ std::optional<CoarraySpec>{}, std::optional<CharLength>{},
282+ std::optional<Initialization>{});
283+ }
284+
278285// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
279286// specified then the type of that iterator is default integer.
280287// [5.0:49:14] The iterator-type must be an integer type.
281288static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
282289 std::list<EntityDecl> entities;
283290
284291 for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
285- EntityDecl entityDecl(
286- /*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
287- std::optional<CoarraySpec>{}, std::optional<CharLength>{},
288- std::optional<Initialization>{});
289- entities.push_back(std::move(entityDecl));
292+ entities.push_back(MakeEntityDecl(std::move(*iter)));
290293 }
291294 return entities;
292295}
@@ -306,6 +309,157 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
306309 makeEntityList(std::move(names)));
307310}
308311
312+ // --- Stylized expression handling -----------------------------------
313+
314+ template <typename A> struct NeverParser {
315+ using resultType = A;
316+ std::optional<resultType> Parse(ParseState &state) const {
317+ // Always fail, but without any messages.
318+ return std::nullopt;
319+ }
320+ };
321+
322+ template <typename A> constexpr auto never() { return NeverParser<A>{}; }
323+
324+ template <typename A, typename B = void> struct NullParser;
325+ template <typename B> struct NullParser<std::optional<B>> {
326+ using resultType = std::optional<B>;
327+ std::optional<resultType> Parse(ParseState &) const {
328+ return resultType{std::nullopt};
329+ }
330+ };
331+
332+ template <typename A> constexpr auto null() { return NullParser<A>{}; }
333+
334+ // OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and
335+ // don't correspond to anything in the source. Their parsers should still
336+ // exist, but they should never be executed.
337+ TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))
338+
339+ TYPE_PARSER( //
340+ construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||
341+ construct<OmpStylizedInstance::Instance>(
342+ sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},
343+ null<std::optional<CallStmt::Chevrons>>(),
344+ parenthesized(optionalList(actualArgSpec))))) ||
345+ construct<OmpStylizedInstance::Instance>(indirect(expr)))
346+
347+ TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))
348+
349+ struct OmpStylizedExpressionParser {
350+ using resultType = OmpStylizedExpression;
351+
352+ std::optional<resultType> Parse(ParseState &state) const {
353+ auto *saved{new ParseState(state)};
354+ auto getSource{verbatim(Parser<OmpStylizedInstance::Instance>{} >> ok)};
355+ if (auto &&ok{getSource.Parse(state)}) {
356+ OmpStylizedExpression result{std::list<OmpStylizedInstance>{}};
357+ result.source = ok->source;
358+ result.state = saved;
359+ // result.v remains empty
360+ return std::move(result);
361+ }
362+ delete saved;
363+ return std::nullopt;
364+ }
365+ };
366+
367+ static void Instantiate(OmpStylizedExpression &ose,
368+ llvm::ArrayRef<const OmpTypeName *> types, llvm::ArrayRef<CharBlock> vars) {
369+ assert(types.size() == vars.size() && "List size mismatch");
370+ ParseState state{DEREF(ose.state)};
371+
372+ std::list<OmpStylizedDeclaration> decls;
373+ for (auto [type, var] : llvm::zip(types, vars)) {
374+ decls.emplace_back(OmpStylizedDeclaration{
375+ common::Reference(*type), MakeEntityDecl(Name{var})});
376+ }
377+
378+ if (auto &&instance{Parser<OmpStylizedInstance::Instance>{}.Parse(state)}) {
379+ ose.v.emplace_back(
380+ OmpStylizedInstance{std::move(decls), std::move(*instance)});
381+ }
382+ }
383+
384+ static void InstantiateForTypes(OmpStylizedExpression &ose,
385+ const OmpTypeNameList &typeNames, llvm::ArrayRef<CharBlock> vars) {
386+ // The variables "vars" need to be declared with the same type.
387+ // For each type in the type list, splat the type into a vector of
388+ // the same size as the variable list, and pass it to Instantiate.
389+ for (const OmpTypeName &t : typeNames.v) {
390+ std::vector<const OmpTypeName *> types(vars.size(), &t);
391+ Instantiate(ose, types, vars);
392+ }
393+ }
394+
395+ static void InstantiateDeclareReduction(OmpDirectiveSpecification &spec) {
396+ // There can be arguments/clauses that don't make sense, that analysis
397+ // is left until semantic checks. Tolerate any unexpected stuff.
398+ auto *rspec{GetFirstArgument<OmpReductionSpecifier>(spec)};
399+ if (!rspec) {
400+ return;
401+ }
402+
403+ const OmpTypeNameList *typeNames{nullptr};
404+
405+ if (auto *cexpr{GetCombinerExpr(*rspec)}) {
406+ typeNames = &std::get<OmpTypeNameList>(rspec->t);
407+
408+ InstantiateForTypes(const_cast<OmpCombinerExpression &>(*cexpr), *typeNames,
409+ OmpCombinerExpression::Variables());
410+ delete cexpr->state;
411+ } else {
412+ // If there are no types, there is nothing else to do.
413+ return;
414+ }
415+
416+ for (const OmpClause &clause : spec.Clauses().v) {
417+ llvm::omp::Clause id{clause.Id()};
418+ if (id == llvm::omp::Clause::OMPC_initializer) {
419+ if (auto *iexpr{GetInitializerExpr(clause)}) {
420+ InstantiateForTypes(const_cast<OmpInitializerExpression &>(*iexpr),
421+ *typeNames, OmpInitializerExpression::Variables());
422+ delete iexpr->state;
423+ }
424+ }
425+ }
426+ }
427+
428+ static void InstantiateStylizedDirective(OmpDirectiveSpecification &spec) {
429+ const OmpDirectiveName &dirName{spec.DirName()};
430+ if (dirName.v == llvm::omp::Directive::OMPD_declare_reduction) {
431+ InstantiateDeclareReduction(spec);
432+ }
433+ }
434+
435+ template <typename P,
436+ typename = std::enable_if_t<
437+ std::is_same_v<typename P::resultType, OmpDirectiveSpecification>>>
438+ struct OmpStylizedInstanceCreator {
439+ using resultType = OmpDirectiveSpecification;
440+ constexpr OmpStylizedInstanceCreator(P p) : parser_(p) {}
441+
442+ std::optional<resultType> Parse(ParseState &state) const {
443+ if (auto &&spec{parser_.Parse(state)}) {
444+ InstantiateStylizedDirective(*spec);
445+ return std::move(spec);
446+ }
447+ return std::nullopt;
448+ }
449+
450+ private:
451+ const P parser_;
452+ };
453+
454+ template <typename P>
455+ OmpStylizedInstanceCreator(P) -> OmpStylizedInstanceCreator<P>;
456+
457+ // --- Parsers for types ----------------------------------------------
458+
459+ TYPE_PARSER( //
460+ sourced(construct<OmpTypeName>(Parser<DeclarationTypeSpec>{})) ||
461+ sourced(construct<OmpTypeName>(Parser<TypeSpec>{})))
462+
309463// --- Parsers for arguments ------------------------------------------
310464
311465// At the moment these are only directive arguments. This is needed for
@@ -366,10 +520,6 @@ struct OmpArgumentListParser {
366520 }
367521};
368522
369- TYPE_PARSER( //
370- construct<OmpTypeName>(Parser<DeclarationTypeSpec>{}) ||
371- construct<OmpTypeName>(Parser<TypeSpec>{}))
372-
373523// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
374524TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
375525 construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
@@ -1065,7 +1215,8 @@ TYPE_PARSER(construct<OmpOtherwiseClause>(
10651215
10661216TYPE_PARSER(construct<OmpWhenClause>(
10671217 maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
1068- maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
1218+ maybe(indirect(
1219+ OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{})))))
10691220
10701221// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
10711222TYPE_PARSER(construct<OmpGrainsizeClause>(
@@ -1780,9 +1931,7 @@ TYPE_PARSER(
17801931TYPE_PARSER(construct<OmpInitializerProc>(Parser<ProcedureDesignator>{},
17811932 parenthesized(many(maybe(","_tok) >> Parser<ActualArgSpec>{}))))
17821933
1783- TYPE_PARSER(construct<OmpInitializerClause>(
1784- construct<OmpInitializerClause>(assignmentStmt) ||
1785- construct<OmpInitializerClause>(Parser<OmpInitializerProc>{})))
1934+ TYPE_PARSER(construct<OmpInitializerClause>(Parser<OmpInitializerExpression>{}))
17861935
17871936// OpenMP 5.2: 7.5.4 Declare Variant directive
17881937TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
@@ -1794,7 +1943,7 @@ TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
17941943TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
17951944 predicated(Parser<OmpDirectiveName>{},
17961945 IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=
1797- Parser<OmpDirectiveSpecification>{})))
1946+ OmpStylizedInstanceCreator( Parser<OmpDirectiveSpecification>{}) )))
17981947
17991948// 2.10.6 Declare Target Construct
18001949TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
@@ -1832,8 +1981,8 @@ TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
18321981 IsDirective(llvm::omp::Directive::OMPD_declare_mapper)) >=
18331982 Parser<OmpDirectiveSpecification>{})))
18341983
1835- TYPE_PARSER(construct<OmpCombinerExpression>(Parser<AssignmentStmt> {}) ||
1836- construct<OmpCombinerExpression>(Parser<FunctionReference> {}))
1984+ TYPE_PARSER(construct<OmpCombinerExpression>(OmpStylizedExpressionParser {}))
1985+ TYPE_PARSER( construct<OmpInitializerExpression>(OmpStylizedExpressionParser {}))
18371986
18381987TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(
18391988 OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))
0 commit comments