forked from OSchip/llvm-project
[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
This commit is contained in:
parent
05d424d165
commit
d489b3807f
|
@ -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},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
Loading…
Reference in New Issue