[PATCH] D132260: [pseudo] Eliminate a false parse of structured binding declaration.

2022-08-23 Thread Haojian Wu via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGf7dc91ad5609: [pseudo] Eliminate a false parse of structured 
binding declaration. (authored by hokein).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D132260/new/

https://reviews.llvm.org/D132260

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


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq 
--print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 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 ref-qualifier_opt [ identifier-list ] 
initializer ;
+simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] 
initializer ; [guard]
 static_assert-declaration := STATIC_ASSERT ( constant-expression ) ;
 static_assert-declaration := STATIC_ASSERT ( constant-expression , 
string-literal ) ;
 empty-declaration := ;
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,27 @@
   return symbolToToken(P.Lookahead) != tok::kw_else;
 }
 
+bool specifiesStructuredBinding(const GuardParams ) {
+  const auto DSS = P.RHS[0];
+  assert(DSS->symbol() == Symbol::decl_specifier_seq);
+
+  auto Length = P.RHS[1]->startTokenIndex() - DSS->startTokenIndex();
+  for (const auto  :
+   P.Tokens.tokens().slice(DSS->startTokenIndex(), Length)) {
+switch (T.Kind) {
+case clang::tok::kw_static:
+case clang::tok::kw_thread_local:
+case clang::tok::kw_auto:
+case clang::tok::kw_const:
+case clang::tok::kw_volatile:
+  break;
+default:
+  return false;
+}
+  }
+  return true;
+}
+
 // 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 +341,18 @@
   {rule::nested_name_specifier::COLONCOLON,
TOKEN_GUARD(coloncolon, Tok.prev().Kind != tok::identifier)},
 
+  // Implement C++ [dcl.pre#6]:
+  //   A simple-declaration with an identifier-list is called a structured
+  //   binding declaration ([dcl.struct.bind]). If the decl-specifier-seq
+  //   contains any decl-specifier other than static, thread_­local, auto,
+  //   or cv-qualifiers, the program is ill-formed.
+  {rule::simple_declaration::
+   
decl_specifier_seq__ref_qualifier__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   specifiesStructuredBinding},
+  {rule::simple_declaration::
+   
decl_specifier_seq__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   specifiesStructuredBinding},
+
   // 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,


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq --print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 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 ref-qualifier_opt [ identifier-list ] initializer ;

[PATCH] D132260: [pseudo] Eliminate a false parse of structured binding declaration.

2022-08-23 Thread Haojian Wu via Phabricator via cfe-commits
hokein updated this revision to Diff 454816.
hokein marked 3 inline comments as done.
hokein added a comment.

address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D132260/new/

https://reviews.llvm.org/D132260

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


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq 
--print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 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 ref-qualifier_opt [ identifier-list ] 
initializer ;
+simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] 
initializer ; [guard]
 static_assert-declaration := STATIC_ASSERT ( constant-expression ) ;
 static_assert-declaration := STATIC_ASSERT ( constant-expression , 
string-literal ) ;
 empty-declaration := ;
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,27 @@
   return symbolToToken(P.Lookahead) != tok::kw_else;
 }
 
+bool specifiesStructuredBinding(const GuardParams ) {
+  const auto DSS = P.RHS[0];
+  assert(DSS->symbol() == Symbol::decl_specifier_seq);
+
+  auto Length = P.RHS[1]->startTokenIndex() - DSS->startTokenIndex();
+  for (const auto  :
+   P.Tokens.tokens().slice(DSS->startTokenIndex(), Length)) {
+switch (T.Kind) {
+case clang::tok::kw_static:
+case clang::tok::kw_thread_local:
+case clang::tok::kw_auto:
+case clang::tok::kw_const:
+case clang::tok::kw_volatile:
+  break;
+default:
+  return false;
+}
+  }
+  return true;
+}
+
 // 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 +341,18 @@
   {rule::nested_name_specifier::COLONCOLON,
TOKEN_GUARD(coloncolon, Tok.prev().Kind != tok::identifier)},
 
+  // Implement C++ [dcl.pre#6]:
+  //   A simple-declaration with an identifier-list is called a structured
+  //   binding declaration ([dcl.struct.bind]). If the decl-specifier-seq
+  //   contains any decl-specifier other than static, thread_­local, auto,
+  //   or cv-qualifiers, the program is ill-formed.
+  {rule::simple_declaration::
+   
decl_specifier_seq__ref_qualifier__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   specifiesStructuredBinding},
+  {rule::simple_declaration::
+   
decl_specifier_seq__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   specifiesStructuredBinding},
+
   // 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,


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,6 @@
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq --print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 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 ref-qualifier_opt [ identifier-list ] initializer ;
+simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] initializer ; [guard]
 static_assert-declaration := 

[PATCH] D132260: [pseudo] Eliminate a false parse of structured binding declaration.

2022-08-22 Thread Sam McCall via Phabricator via cfe-commits
sammccall accepted this revision.
sammccall added inline comments.
This revision is now accepted and ready to land.



Comment at: clang-tools-extra/pseudo/lib/cxx/CXX.cpp:164
 
+bool isStructuredBinding(const ForestNode* N) {
+  assert(N->symbol() == Symbol::decl_specifier_seq);

nit: specifiesStructuredBinding?
(because the structured binding itself is something bigger)



Comment at: clang-tools-extra/pseudo/lib/cxx/CXX.cpp:166
+  assert(N->symbol() == Symbol::decl_specifier_seq);
+  for (const auto  : N->descendants()) {
+if (Child.kind() == ForestNode::Terminal) {

If you're going to iterate over tokens, it seems more direct (and cheaper) to 
do it directly:
`for (const Tok& : P.Tokens.tokens(RHS[0].startTokenIndex(), 
RHS[1].startTokenIndex()))`



Comment at: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp:1
+
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq 
--print-forest | FileCheck %s

nit: drop blank line


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D132260/new/

https://reviews.llvm.org/D132260

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D132260: [pseudo] Eliminate a false parse of structured binding declaration.

2022-08-19 Thread Haojian Wu via Phabricator via cfe-commits
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.

Using the guard to implement part of the rule https://eel.is/c++draft/dcl.pre#6.

  void foo() {
// can be parsed as
//   - structured-binding declaration (a false parse)
//   - assignment expression
array[index] = value;
  }


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132260

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


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,7 @@
+
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq 
--print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 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 ref-qualifier_opt [ identifier-list ] 
initializer ;
+simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] 
initializer ; [guard]
 static_assert-declaration := STATIC_ASSERT ( constant-expression ) ;
 static_assert-declaration := STATIC_ASSERT ( constant-expression , 
string-literal ) ;
 empty-declaration := ;
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,26 @@
   return symbolToToken(P.Lookahead) != tok::kw_else;
 }
 
+bool isStructuredBinding(const ForestNode* N) {
+  assert(N->symbol() == Symbol::decl_specifier_seq);
+  for (const auto  : N->descendants()) {
+if (Child.kind() == ForestNode::Terminal) {
+  auto Kind = symbolToToken(Child.symbol());
+  switch (Kind) {
+  case clang::tok::kw_static:
+  case clang::tok::kw_thread_local:
+  case clang::tok::kw_auto:
+  case clang::tok::kw_const:
+  case clang::tok::kw_volatile:
+break;
+  default:
+return false;
+  }
+}
+  }
+  return true;
+}
+
 // 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 +340,18 @@
   {rule::nested_name_specifier::COLONCOLON,
TOKEN_GUARD(coloncolon, Tok.prev().Kind != tok::identifier)},
 
+  // Implement C++ [dcl.pre#6]:
+  //   A simple-declaration with an identifier-list is called a structured
+  //   binding declaration ([dcl.struct.bind]). If the decl-specifier-seq
+  //   contains any decl-specifier other than static, thread_­local, auto,
+  //   or cv-qualifiers, the program is ill-formed.
+  {rule::simple_declaration::
+   
decl_specifier_seq__ref_qualifier__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   GUARD(isStructuredBinding(P.RHS[0]))},
+  {rule::simple_declaration::
+   
decl_specifier_seq__L_SQUARE__identifier_list__R_SQUARE__initializer__SEMI,
+   GUARD(isStructuredBinding(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,


Index: clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
===
--- /dev/null
+++ clang-tools-extra/pseudo/test/cxx/structured-binding.cpp
@@ -0,0 +1,7 @@
+
+// RUN: clang-pseudo -grammar=cxx -source=%s --start-symbol=statement-seq --print-forest | FileCheck %s
+
+// Verify there is no false parse of the structured binding declaration.
+ABC[post] = abc;
+// CHECK: statement-seq~expression-statement := expression ;
+// CHECK: postfix-expression [ expr-or-braced-init-list ]
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
@@ -330,7 +330,7 @@
 nodeclspec-function-declaration := function-declarator ;
 alias-declaration := USING IDENTIFIER = defining-type-id ;
 simple-declaration := decl-specifier-seq