Build failure when attempting to build flang with c++20

We have an internal contributor that’s looking at fixing c++20 related failures, focusing on aggregate initialization issues. See [test] Fix aggregate initialization incompatible with c++20 · llvm/llvm-project@f039a2c · GitHub for a related change. They ran into this one in flang (with flang/CMakeLists.txt modified to use set(CMAKE_CXX_STANDARD 20)):

FAILED: tools/flang/lib/Parser/CMakeFiles/obj.FortranParser.dir/openmp-parsers.cpp.o
/home/rupprecht/installs/llvm-src/bin/clang++ -DFLANG_INCLUDE_TESTS=1 -DFLANG_LITTLE_ENDIAN=1 -DGTEST_HAS_RTTI=0 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/rupprecht/src/llvm-build/dev/tools/flang/lib/Parser -I/home/rupprecht/src/llvm-project/flang/lib/Parser -I/home/rupprecht/src/llvm-project/flang/include -I/home/rupprecht/src/llvm-build/dev/tools/flang/include -I/home/rupprecht/src/llvm-build/dev/include -I/home/rupprecht/src/llvm-project/llvm/include -isystem /home/rupprecht/src/llvm-project/llvm/../mlir/include -isystem /home/rupprecht/src/llvm-build/dev/tools/mlir/include -isystem /home/rupprecht/src/llvm-build/dev/tools/clang/include -isystem /home/rupprecht/src/llvm-project/llvm/../clang/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -Wno-deprecated-copy -Wno-string-conversion -Wno-ctad-maybe-unsupported -Wno-unused-command-line-argument -Wstring-conversion           -Wcovered-switch-default -Wno-nested-anon-types -g -DDEBUGF18  -fno-exceptions -fno-rtti -gsplit-dwarf -std=c++20 -MD -MT tools/flang/lib/Parser/CMakeFiles/obj.FortranParser.dir/openmp-parsers.cpp.o -MF tools/flang/lib/Parser/CMakeFiles/obj.FortranParser.dir/openmp-parsers.cpp.o.d -o tools/flang/lib/Parser/CMakeFiles/obj.FortranParser.dir/openmp-parsers.cpp.o -c /home/rupprecht/src/llvm-project/flang/lib/Parser/openmp-parsers.cpp
In file included from /home/rupprecht/src/llvm-project/flang/lib/Parser/openmp-parsers.cpp:12:
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:754:16: error: call to deleted constructor of 'Fortran::parser::Verbatim'
        return RESULT{};
               ^     ~~
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:737:16: note: in instantiation of member function 'Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>::ParseOne' requested here
        return ParseOne(state);
               ^
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:920:25: note: in instantiation of member function 'Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>::Parse' requested here
    auto result{parser_.Parse(state)};
                        ^
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:598:49: note: in instantiation of member function 'Fortran::parser::SourcedParser<Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>>::Parse' requested here
      (std::get<J>(args) = std::get<J>(parsers).Parse(state),
                                                ^
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:741:13: note: in instantiation of function template specialization 'Fortran::parser::ApplyHelperArgs<Fortran::parser::SourcedParser<Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>>, Fortran::parser::Parser<Fortran::parser::OmpCancelType>, 0UL, 1UL>' requested here
        if (ApplyHelperArgs(parsers_, results, state, Sequence{})) {
            ^
/home/rupprecht/src/llvm-project/flang/lib/Parser/basic-parsers.h:920:25: note: in instantiation of member function 'Fortran::parser::ApplyConstructor<Fortran::parser::OpenMPCancellationPointConstruct, Fortran::parser::SourcedParser<Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>>, Fortran::parser::Parser<Fortran::parser::OmpCancelType>>::Parse' requested here
    auto result{parser_.Parse(state)};
                        ^
/home/rupprecht/src/llvm-project/flang/lib/Parser/openmp-parsers.cpp:350:1: note: in instantiation of member function 'Fortran::parser::SourcedParser<Fortran::parser::ApplyConstructor<Fortran::parser::OpenMPCancellationPointConstruct, Fortran::parser::SourcedParser<Fortran::parser::ApplyConstructor<Fortran::parser::Verbatim, Fortran::parser::TokenStringMatch<false, false>>>, Fortran::parser::Parser<Fortran::parser::OmpCancelType>>>::Parse' requested here
TYPE_PARSER(sourced(construct<OpenMPCancellationPointConstruct>(
^
/home/rupprecht/src/llvm-project/flang/lib/Parser/type-parser-implementation.h:29:19: note: expanded from macro 'TYPE_PARSER'
    return parser.Parse(state); \
                  ^
/home/rupprecht/src/llvm-project/flang/include/flang/Parser/parse-tree.h:273:15: note: 'Verbatim' has been explicitly marked deleted here
  BOILERPLATE(Verbatim);
              ^
1 error generated.

The issue is that in c++20, declaring (or deleting) constructors makes them no longer constructible with aggregate initialization. The straightforward fix is to just make it a plain struct, and don’t delete any constuctors. That way, we can construct this either as Verbatim{} for the no-op case or Verbatim{.source=...} for the 1-arg case:

struct Verbatim {
  BOILERPLATE(Verbatim); // <-- delete this line
  using EmptyTrait = std::true_type;
  CharBlock source;
};

However, parse-tree.h also has this cautionary comment that all these constructors should be deleted:

// Parse tree node class types do not have default constructors.  They
// explicitly declare "T() {} = delete;" to make this clear.  This restriction
// prevents the introduction of what would be a viral requirement to include
// std::monostate among most std::variant<> discriminated union members.

// Parse tree node class types do not have copy constructors or copy assignment
// operators.  They are explicitly declared "= delete;" to make this clear,
// although a C++ compiler wouldn't default them anyway due to the presence
// of explicitly defaulted move constructors and move assignments.

This comment makes it clear that the default constructor is not desired, but that seems to be effectively side stepped when invoking RESULT{} (where RESULT expands to Verbatim in this case). With c++20, this workaround is no longer valid. So while c++20 isn’t necessarily something flang needs to agree on supporting, it also seems that c++20 is just pointing out an existing issue with the code.

Is anyone familiar with this structure to advise on the best fix to make for this?

I remember @klausler worked on that.

The fix should be:

struct Verbatim {
  COPY_AND_ASSIGN_BOILERPLATE(Verbatim);
  constexpr Verbatim() {}
  using EmptyTrait = std::true_type;
  CharBlock source;
};