[clang-tools-extra] d489b38 - [pseudo] Implement a guard to determine function declarator.
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 19 00:49:30 PDT 2022
Author: Haojian Wu
Date: 2022-07-19T09:44:45+02:00
New Revision: d489b3807f096584175c321ce7f20e9dcd49b1da
URL: https://github.com/llvm/llvm-project/commit/d489b3807f096584175c321ce7f20e9dcd49b1da
DIFF: https://github.com/llvm/llvm-project/commit/d489b3807f096584175c321ce7f20e9dcd49b1da.diff
LOG: [pseudo] Implement a guard to determine function declarator.
This eliminates some simple-declaration/function-definition false
parses.
- implement a function to determine whether a declarator ForestNode is a
function declarator;
- extend the standard declarator to two guarded function-declarator and
non-function-declarator nonterminals;
Differential Revision: https://reviews.llvm.org/D129222
Added:
Modified:
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-func-parameters.cpp
clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
clang-tools-extra/pseudo/test/glr.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/pseudo/lib/cxx/CXX.cpp b/clang-tools-extra/pseudo/lib/cxx/CXX.cpp
index 9a03422153f06..d6c056a25e365 100644
--- a/clang-tools-extra/pseudo/lib/cxx/CXX.cpp
+++ b/clang-tools-extra/pseudo/lib/cxx/CXX.cpp
@@ -46,6 +46,66 @@ bool guardExport(llvm::ArrayRef<const ForestNode *> RHS,
return Tokens.tokens()[RHS.front()->startTokenIndex()].text() == "export";
}
+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},
@@ -53,6 +113,8 @@ llvm::DenseMap<ExtensionID, RuleGuard> buildGuards() {
{(ExtensionID)Extension::Import, guardImport},
{(ExtensionID)Extension::Export, guardExport},
{(ExtensionID)Extension::Module, guardModule},
+ {(ExtensionID)Extension::FunctionDeclarator, guardFunction},
+ {(ExtensionID)Extension::NonFunctionDeclarator, guardNonFunction},
};
}
diff --git a/clang-tools-extra/pseudo/lib/cxx/cxx.bnf b/clang-tools-extra/pseudo/lib/cxx/cxx.bnf
index 08384af9d9399..4e434b1e037cc 100644
--- a/clang-tools-extra/pseudo/lib/cxx/cxx.bnf
+++ b/clang-tools-extra/pseudo/lib/cxx/cxx.bnf
@@ -332,7 +332,7 @@ block-declaration := using-directive
block-declaration := static_assert-declaration
block-declaration := alias-declaration
block-declaration := opaque-enum-declaration
-nodeclspec-function-declaration := declarator ;
+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 ;
@@ -402,8 +402,19 @@ placeholder-type-specifier := type-constraint_opt AUTO
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
+#! The standard grammar allows:
+#! 1) an initializer with any declarator, including a function declarator, this
+#! creates an ambiguity where a function definition is misparsed as a simple
+#! declaration;
+#! 2) an function-body with any declarator, includeing a non-function
+#! declarator, this creates an ambiguity whwere a simple-declaration is
+#! misparsed as a function-definition;
+#! We extend the standard declarator to function-declarator and non-function-declarator
+#! to eliminate these false parses.
+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 +483,8 @@ designator := [ expression ]
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 ;
diff --git a/clang-tools-extra/pseudo/test/cxx/declarator-function.cpp b/clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
index 59dccf993af47..4d7972807c6db 100644
--- a/clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
+++ b/clang-tools-extra/pseudo/test/cxx/declarator-function.cpp
@@ -1,11 +1,9 @@
// 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
+// CHECK: function-definition := decl-specifier-seq function-declarator function-body
+// CHECK-NOT: simple-declaration
diff --git a/clang-tools-extra/pseudo/test/cxx/declarator-var.cpp b/clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
index 057ec55b1c925..5aedd8037513f 100644
--- a/clang-tools-extra/pseudo/test/cxx/declarator-var.cpp
+++ b/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
diff --git a/clang-tools-extra/pseudo/test/cxx/recovery-func-parameters.cpp b/clang-tools-extra/pseudo/test/cxx/recovery-func-parameters.cpp
index d3007c3fb4bc6..0b41f881fa3bf 100644
--- a/clang-tools-extra/pseudo/test/cxx/recovery-func-parameters.cpp
+++ b/clang-tools-extra/pseudo/test/cxx/recovery-func-parameters.cpp
@@ -1,8 +1,8 @@
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
void foo(complete garbage???) {}
-// CHECK: translation-unit~function-definition := decl-specifier-seq declarator function-body
+// CHECK: translation-unit~function-definition := decl-specifier-seq function-declarator function-body
// CHECK-NEXT: ├─decl-specifier-seq~VOID := tok[0]
-// CHECK-NEXT: ├─declarator~noptr-declarator := noptr-declarator parameters-and-qualifiers
+// CHECK-NEXT: ├─function-declarator~noptr-declarator := noptr-declarator parameters-and-qualifiers
// CHECK-NEXT: │ ├─noptr-declarator~IDENTIFIER := tok[1]
// CHECK-NEXT: │ └─parameters-and-qualifiers := ( parameter-declaration-clause [recover=Brackets] )
// CHECK-NEXT: │ ├─( := tok[2]
diff --git a/clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp b/clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
index 283c53d78128d..38216ad964772 100644
--- a/clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
+++ b/clang-tools-extra/pseudo/test/cxx/recovery-init-list.cpp
@@ -3,7 +3,7 @@ auto x = { complete garbage };
// 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
diff --git a/clang-tools-extra/pseudo/test/glr.cpp b/clang-tools-extra/pseudo/test/glr.cpp
index 0eb19fba2ecc6..24b2ac05f6f1b 100644
--- a/clang-tools-extra/pseudo/test/glr.cpp
+++ b/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?
More information about the cfe-commits
mailing list