[PATCH] D131762: [pseudo][wip] Enforce the C++ rule for the optional init-declarator-list.

Haojian Wu via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 12 05:00:07 PDT 2022


hokein created this revision.
hokein added a reviewer: sammccall.
Herald added a project: All.
hokein requested review of this revision.
Herald added a subscriber: alextsao1999.
Herald added a project: clang-tools-extra.

Basically it implements the https://eel.is/c++draft/dcl.pre#5 rule.

The motivation is to eliminate a false parse (simple declaration) for the enum
declaration.

  // A simple declaration without a declarator
  // or an opaque-enum-declaration
  enum a;

However, it has some negative effects on broken code (with the single-type
decl-specifier-seq guard):

- break the `const int;` case (which we used to parse as a declaration without declarator), now we fails to parse, because it is invalid code per the C++ spec.
- regress the `const Foo;` case, now we parse it as a declaration with a declarator named `Foo` and `const` as the decl-specifier-seq, vs we used to parsed as a declaration without declarator (which is better IMO);

Just post here to get thoughts about it:
My feeling is that this degrades the parser a lot for the little benefit we gain,
we probably don't move forward with this approach.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131762

Files:
  clang-tools-extra/pseudo/lib/cxx/CXX.cpp
  clang-tools-extra/pseudo/lib/cxx/cxx.bnf


Index: clang-tools-extra/pseudo/lib/cxx/cxx.bnf
===================================================================
--- clang-tools-extra/pseudo/lib/cxx/cxx.bnf
+++ clang-tools-extra/pseudo/lib/cxx/cxx.bnf
@@ -334,7 +334,7 @@
 block-declaration := opaque-enum-declaration
 nodeclspec-function-declaration := function-declarator ;
 alias-declaration := USING IDENTIFIER = defining-type-id ;
-simple-declaration := decl-specifier-seq init-declarator-list_opt ;
+simple-declaration := decl-specifier-seq init-declarator-list_opt ; [guard]
 simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] initializer ;
 static_assert-declaration := STATIC_ASSERT ( constant-expression ) ;
 static_assert-declaration := STATIC_ASSERT ( constant-expression , string-literal ) ;
Index: clang-tools-extra/pseudo/lib/cxx/CXX.cpp
===================================================================
--- clang-tools-extra/pseudo/lib/cxx/CXX.cpp
+++ clang-tools-extra/pseudo/lib/cxx/CXX.cpp
@@ -161,6 +161,59 @@
   return symbolToToken(P.Lookahead) != tok::kw_else;
 }
 
+bool canOmitDeclarator(const ForestNode* N) {
+  // Returns true if a decl-specifier is
+  //   a class-specifier
+  //   or an elaborated-type-specifier with class-key, or an enum_specifier.
+  auto hasTargetSpecifier = [](const ForestNode *N, auto &hasTargetSpecifier) {
+    if (N->kind() == ForestNode::Opaque)
+      return false;
+    if (N->kind() == ForestNode::Ambiguous)
+      return llvm::all_of(N->alternatives(),
+                          std::bind(hasTargetSpecifier, std::placeholders::_1,
+                                    hasTargetSpecifier));
+
+    switch (N->rule()) {
+    case rule::defining_type_specifier::type_specifier:
+    case rule::defining_type_specifier::enum_specifier:
+    case rule::type_specifier::elaborated_type_specifier:
+    case rule::decl_specifier::defining_type_specifier:
+      return hasTargetSpecifier(N->elements()[0], hasTargetSpecifier);
+
+    case rule::enum_specifier::enum_head__L_BRACE__R_BRACE:
+    case rule::enum_specifier::
+        enum_head__L_BRACE__enumerator_list__COMMA__R_BRACE:
+    case rule::enum_specifier::enum_head__L_BRACE__enumerator_list__R_BRACE:
+    case rule::elaborated_type_specifier::
+        class_key__nested_name_specifier__IDENTIFIER:
+    case rule::elaborated_type_specifier::
+        class_key__nested_name_specifier__simple_template_id:
+    case rule::elaborated_type_specifier::
+        class_key__nested_name_specifier__TEMPLATE__simple_template_id:
+    case rule::elaborated_type_specifier::class_key__simple_template_id:
+    case rule::elaborated_type_specifier::class_key__IDENTIFIER:
+    case rule::defining_type_specifier::class_specifier:
+      return true;
+    default:
+      return false;
+    }
+  };
+  while (true) {
+    switch (N->rule()) {
+    case cxx::rule::decl_specifier_seq::decl_specifier:
+      return hasTargetSpecifier(N->elements()[0], hasTargetSpecifier);
+    case cxx::rule::decl_specifier_seq::decl_specifier__decl_specifier_seq:
+      if (hasTargetSpecifier(N->elements()[0], hasTargetSpecifier))
+        return true;
+      N = N->elements()[1];
+      break;
+    default:
+      LLVM_DEBUG(llvm::errs() << "Unhandled rule " << N->rule() << "\n");
+      llvm_unreachable("decl_specifier_seq be exhaustive!");
+    }
+  }
+  return false;
+}
 // Whether this e.g. decl-specifier contains an "exclusive" type such as a class
 // name, and thus can't combine with a second exclusive type.
 //
@@ -320,6 +373,15 @@
       {rule::nested_name_specifier::COLONCOLON,
        TOKEN_GUARD(coloncolon, Tok.prev().Kind != tok::identifier)},
 
+      // Implement C++ [dcl.pre#5]:
+      //   In a simple-declaration, the optional init-declarator-list can be
+      //   omitted only when declaring a class ([class.pre]) or enumeration
+      //   ([dcl.enum]), that is, when the decl-specifier-seq contains either a
+      //   class-specifier, an elaborated-type-specifier with a class-key
+      //   ([class.name]), or an enum-specifier.
+      {rule::simple_declaration::decl_specifier_seq__SEMI,
+       GUARD(canOmitDeclarator(P.RHS[0]))},
+
       // The grammar distinguishes (only) user-defined vs plain string literals,
       // where the clang lexer distinguishes (only) encoding types.
       {rule::user_defined_string_literal_chunk::STRING_LITERAL,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D131762.452144.patch
Type: text/x-patch
Size: 4374 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20220812/8a4042d5/attachment.bin>


More information about the cfe-commits mailing list