[flang-commits] [flang] [flang][OpenMP] Implement OpenMP stylized expressions (PR #165049)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Mon Oct 27 06:50:29 PDT 2025
================
@@ -306,6 +309,207 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
makeEntityList(std::move(names)));
}
+// --- Stylized expression handling -----------------------------------
+
+// OpenMP has a concept of am "OpenMP stylized expression". Syntactially
+// it looks like a typical Fortran expression (or statement), except:
+// - the only variables allowed in it are OpenMP special variables, the
+// exact set of these variables depends on the specific case of the
+// stylized expression
+// - the special OpenMP variables present may assume one or more types,
+// and the expression should be semantically valid for each type.
+//
+// The stylized expression can be thought of as a template, which will be
+// instantiated for each type provided somewhere in the context in which
+// the stylized expression appears.
+//
+// AST nodes:
+// - OmpStylizedExpression: contains the source string for the expression,
+// plus the list of instances (OmpStylizedInstance).
+// - OmpStylizedInstance: corresponds to the instantiation of the stylized
+// expression for a specific type. The way that the type is specified is
+// by creating declarations (OmpStylizedDeclaration) for the special
+// variables. Together with the AST tree corresponding to the stylized
+// expression the instantiation has enough information for semantic
+// analysis. Each instance has its own scope, and the special variables
+// have their own Symbol's (local to the scope).
+// - OmpStylizedDeclaration: encapsulates the information that the visitors
+// in resolve-names can use to "emulate" a declaration for a special
+// variable and allow name resolution in the instantiation AST to work.
+//
+// Implementation specifics:
+// The semantic analysis stores "evaluate::Expr" in each AST node rooted
+// in parser::Expr (in the typedExpr member). The evaluate::Expr is specific
+// to a given type, and so to allow different types for a given expression,
+// for each type a separate copy of the parsee::Expr subtree is created.
+// Normally, AST nodes are non-copyable (copy-ctor is deleted), so to create
+// several copies of a subtree, the same source string is parsed several
+// times. The ParseState member in OmpStylizedExpression is the parser state
+// immediately before the stylized expression.
+//
+// Initially, when OmpStylizedExpression is first created, the expression is
+// parsed as if it was an actual code, but this parsing is only done to
+// establish where the stylized expression ends (in the source). The source
+// and the initial parser state are store in the object, and the instance
+// list is empty.
+// Once the parsing of the containing OmpDirectiveSpecification completes,
+// a post-processing "parser" (OmpStylizedInstanceCreator) executes. This
+// post-processor examines the directive specification to see if it expects
+// any stylized expressions to be contained in it, and then instantiates
+// them for each such directive.
+
+template <typename A> struct NeverParser {
+ using resultType = A;
+ std::optional<resultType> Parse(ParseState &state) const {
+ // Always fail, but without any messages.
+ return std::nullopt;
+ }
+};
+
+template <typename A> constexpr auto never() { return NeverParser<A>{}; }
+
+template <typename A, typename B = void> struct NullParser;
+template <typename B> struct NullParser<std::optional<B>> {
+ using resultType = std::optional<B>;
+ std::optional<resultType> Parse(ParseState &) const {
+ return resultType{std::nullopt};
+ }
+};
+
+template <typename A> constexpr auto null() { return NullParser<A>{}; }
+
+// OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and
+// don't correspond to anything in the source. Their parsers should still
+// exist, but they should never be executed.
+TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))
+
+TYPE_PARSER( //
+ construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||
+ construct<OmpStylizedInstance::Instance>(
+ sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},
+ null<std::optional<CallStmt::Chevrons>>(),
+ parenthesized(optionalList(actualArgSpec))))) ||
+ construct<OmpStylizedInstance::Instance>(indirect(expr)))
+
+TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))
----------------
kparzysz wrote:
Done
https://github.com/llvm/llvm-project/pull/165049
More information about the flang-commits
mailing list