C++14/17 features used in Flang#

The C++ dialect used in this project constitutes a subset of the standard C++ programming language and library features. We want our dialect to be compatible with the LLVM C++ language subset that will be in use at the time that we integrate with that project. We also want to maximize portability, future-proofing, compile-time error checking, and use of best practices.

To that end, we have a C++ style guide (q.v.) that lays out the details of how our C++ code should look and gives guidance about feature usage.

We have chosen to use some features of the recent C++17 language standard in Flang. The most important of these are:

  • sum types (discriminated unions) in the form of std::variant

  • using template parameter packs

  • generic lambdas with auto argument types

  • product types in the form of std::tuple

  • std::optional

(std::tuple is actually a C++11 feature, but I include it in this list because it’s not particularly well known.)

Sum types#

First, some background information to explain the need for sum types in Flang.

Fortran is notoriously problematic to lex and parse, as tokenization depends on the state of the partial parse; the language has no reserved words in the sense that C++ does. Fortran parsers implemented with distinct lexing and parsing phases (generated by hand or with tools) need to implement them as coroutines with complicated state, and experience has shown that it’s hard to get them right and harder to extend them as the language evolves.

Alternatively, with the use of backtracking, one can parse Fortran with a unified lexer/parser. We have chosen to do so because it is simpler and should reduce both initial bugs and long-term maintenance.

Specifically, Flang’s parser uses the technique of recursive descent with backtracking. It is constructed as the incremental composition of pure parsing functions that each, when given a context (location in the input stream plus some state), either succeeds or fails to recognize some piece of Fortran. On success, they return a new state and some semantic value, and this is usually an instance of a C++ struct type that encodes the semantic content of a production in the Fortran grammar.

This technique allows us to specify both the Fortran grammar and the representation of successfully parsed programs with C++ code whose functions and data structures correspond closely to the productions of Fortran.

The specification of Fortran uses a form of BNF with alternatives, optional elements, sequences, and lists. Each of these constructs in the Fortran grammar maps directly in Flang’s parser to both the means of combining other parsers as alternatives, &c., and to the declarations of the parse tree data structures that represent the results of successful parses. Move semantics are used in the parsing functions to acquire and combine the results of sub-parses into the result of a larger parse.

To represent nodes in the Fortran parse tree, we need a means of handling sum types for productions that have multiple alternatives. The bounded polymorphism supplied by the C++17