hokein updated this revision to Diff 444976.
hokein added a comment.
rebase and address the main comment -- encoding the function-declarator into
the grammar.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D129222/new/
https://reviews.llvm.org/D129222
Files:
clang-tools-extra/pseudo/lib/cxx/CXX.cpp
clang-tools-extra/pseudo/lib/cxx/cxx.bnf
clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
clang-tools-extra/pseudo/test/glr.cpp
Index: clang-tools-extra/pseudo/test/glr.cpp
===================================================================
--- clang-tools-extra/pseudo/test/glr.cpp
+++ clang-tools-extra/pseudo/test/glr.cpp
@@ -1,4 +1,4 @@
-// RUN: clang-pseudo -grammar=%cxx-bnf-file -source=%s --print-forest -print-statistics | FileCheck %s
+// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest -print-statistics | FileCheck %s
void foo() {
T* a; // a multiply expression or a pointer declaration?
Index: clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
===================================================================
--- clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
+++ clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
@@ -3,7 +3,7 @@
// CHECK: translation-unit~simple-declaration
// CHECK-NEXT: ââdecl-specifier-seq~AUTO := tok[0]
// CHECK-NEXT: ââinit-declarator-list~init-declarator
-// CHECK-NEXT: â ââdeclarator~IDENTIFIER := tok[1]
+// CHECK-NEXT: â âânon-function-declarator~IDENTIFIER := tok[1]
// CHECK-NEXT: â ââinitializer~brace-or-equal-initializer
// CHECK-NEXT: â ââ= := tok[2]
// CHECK-NEXT: â ââinitializer-clause~braced-init-list
Index: clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
===================================================================
--- clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
+++ clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
@@ -1,11 +1,9 @@
// The standard grammar allows an function-body to use any declarator, including
// a non-function declarator. This creates an ambiguity where a
// simple-declaration is misparsed as a function-definition.
-// FIXME: eliminate this false parse.
-// XFAIL: *
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
void (*s)(){};
// CHECK-NOT: function-definition
-// CHECK: init-declarator := declarator initializer
+// CHECK: init-declarator := non-function-declarator initializer
// CHECK-NOT: function-definition
Index: clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
===================================================================
--- clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
+++ clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
@@ -1,11 +1,28 @@
// The standard grammar allows an init-list with any declarator, including
// a function declarator. This creates an ambiguity where a function-definition
// is misparsed as a simple-declaration.
-// FIXME: eliminate this false parse.
-// XFAIL: *
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
-void s(){};
-// CHECK-NOT: simple-declaration
-// CHECK: function-definition := decl-specifier-seq declarator
-// function-body CHECK-NOT: simple-declaration
+void s() {};
+// CHECK: ââdeclaration-seq~function-definition := decl-specifier-seq function-declarator function-body
+// CHECK-NEXT: â ââdecl-specifier-seq~VOID := tok[0]
+// CHECK-NEXT: â ââfunction-declarator~noptr-declarator := noptr-declarator parameters-and-qualifiers
+// CHECK-NEXT: â â âânoptr-declarator~IDENTIFIER := tok[1]
+// CHECK-NEXT: â â ââparameters-and-qualifiers := ( )
+// CHECK-NEXT: â â ââ( := tok[2]
+// CHECK-NEXT: â â ââ) := tok[3]
+// CHECK-NEXT: â ââfunction-body~compound-statement := { }
+// CHECK-NEXT: â ââ{ := tok[4]
+// CHECK-NEXT: â ââ} := tok[5]
+// CHECK-NEXT: ââdeclaration~; := tok[6]
+
+// Should not parse as a function-definition.
+int s2 {};
+// CHECK-NEXT: declaration~simple-declaration := decl-specifier-seq init-declarator-list ;
+// CHECK-NEXT: ââdecl-specifier-seq~INT := tok[7]
+// CHECK-NEXT: ââinit-declarator-list~init-declarator := non-function-declarator initializer
+// CHECK-NEXT: â âânon-function-declarator~IDENTIFIER := tok[8]
+// CHECK-NEXT: â ââinitializer~braced-init-list := { }
+// CHECK-NEXT: â ââ{ := tok[9]
+// CHECK-NEXT: â ââ} := tok[10]
+// CHECK-NEXT: ââ; := tok[11]
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
@@ -402,8 +402,10 @@
placeholder-type-specifier := type-constraint_opt DECLTYPE ( AUTO )
init-declarator-list := init-declarator
init-declarator-list := init-declarator-list , init-declarator
-init-declarator := declarator initializer_opt
-init-declarator := declarator requires-clause
+init-declarator := non-function-declarator initializer_opt
+init-declarator := function-declarator requires-clause_opt
+function-declarator := declarator [guard=FunctionDeclarator]
+non-function-declarator := declarator [guard=NonFunctionDeclarator]
declarator := ptr-declarator
declarator := noptr-declarator parameters-and-qualifiers trailing-return-type
ptr-declarator := noptr-declarator
@@ -472,8 +474,8 @@
expr-or-braced-init-list := expression
expr-or-braced-init-list := braced-init-list
# dcl.fct
-function-definition := decl-specifier-seq_opt declarator virt-specifier-seq_opt function-body
-function-definition := decl-specifier-seq_opt declarator requires-clause function-body
+function-definition := decl-specifier-seq_opt function-declarator virt-specifier-seq_opt function-body
+function-definition := decl-specifier-seq_opt function-declarator requires-clause function-body
function-body := ctor-initializer_opt compound-statement
function-body := function-try-block
function-body := = DEFAULT ;
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
@@ -34,10 +34,72 @@
return Tokens.tokens()[RHS.front()->startTokenIndex()].text() == "final";
}
+bool isFunctionDeclarator(const ForestNode *Declarator) {
+ assert(Declarator->symbol() == (SymbolID)(cxx::Symbol::declarator));
+ bool IsFunction = false;
+ using cxx::Rule;
+ while (true) {
+ // not well-formed code, return the best guess.
+ if (Declarator->kind() != ForestNode::Sequence)
+ return IsFunction;
+
+ switch ((cxx::Rule)Declarator->rule()) {
+ case Rule::noptr_declarator_0declarator_id: // reached the bottom
+ return IsFunction;
+ // *X is a nonfunction (unless X is a function).
+ case Rule::ptr_declarator_0ptr_operator_1ptr_declarator:
+ Declarator = Declarator->elements()[1];
+ IsFunction = false;
+ continue;
+ // X() is a function (unless X is a pointer or similar)
+ case Rule::
+ declarator_0noptr_declarator_1parameters_and_qualifiers_2trailing_return_type:
+ case Rule::noptr_declarator_0noptr_declarator_1parameters_and_qualifiers:
+ Declarator = Declarator->elements()[0];
+ IsFunction = true;
+ continue;
+ // X[] is an array (unless X is a pointer or function)
+ case Rule::
+ noptr_declarator_0noptr_declarator_1l_square_2constant_expression_3r_square:
+ case Rule::noptr_declarator_0noptr_declarator_1l_square_2r_square:
+ Declarator = Declarator->elements()[0];
+ IsFunction = false;
+ continue;
+ // (X) is whatever X is.
+ case Rule::noptr_declarator_0l_paren_1ptr_declarator_2r_paren:
+ Declarator = Declarator->elements()[1];
+ continue;
+ case Rule::ptr_declarator_0noptr_declarator:
+ case Rule::declarator_0ptr_declarator:
+ Declarator = Declarator->elements()[0];
+ continue;
+
+ default:
+ assert(false && "unhandled declarator for IsFunction");
+ return IsFunction;
+ }
+ }
+ llvm_unreachable("unreachable");
+}
+bool guardFunction(llvm::ArrayRef<const ForestNode *> RHS,
+ const TokenStream &Tokens) {
+ assert(RHS.size() == 1 &&
+ RHS.front()->symbol() == (SymbolID)(cxx::Symbol::declarator));
+ return isFunctionDeclarator(RHS.front());
+}
+bool guardNonFunction(llvm::ArrayRef<const ForestNode *> RHS,
+ const TokenStream &Tokens) {
+ assert(RHS.size() == 1 &&
+ RHS.front()->symbol() == (SymbolID)(cxx::Symbol::declarator));
+ return !isFunctionDeclarator(RHS.front());
+}
+
llvm::DenseMap<ExtensionID, RuleGuard> buildGuards() {
return {
{(ExtensionID)Extension::Override, guardOverride},
{(ExtensionID)Extension::Final, guardFinal},
+ {(ExtensionID)Extension::FunctionDeclarator, guardFunction},
+ {(ExtensionID)Extension::NonFunctionDeclarator, guardNonFunction},
};
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits