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";
|
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() {
|
llvm::DenseMap<ExtensionID, RuleGuard> buildGuards() {
|
||||||
return {
|
return {
|
||||||
{(ExtensionID)Extension::Override, guardOverride},
|
{(ExtensionID)Extension::Override, guardOverride},
|
||||||
|
@ -53,6 +113,8 @@ llvm::DenseMap<ExtensionID, RuleGuard> buildGuards() {
|
||||||
{(ExtensionID)Extension::Import, guardImport},
|
{(ExtensionID)Extension::Import, guardImport},
|
||||||
{(ExtensionID)Extension::Export, guardExport},
|
{(ExtensionID)Extension::Export, guardExport},
|
||||||
{(ExtensionID)Extension::Module, guardModule},
|
{(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 := static_assert-declaration
|
||||||
block-declaration := alias-declaration
|
block-declaration := alias-declaration
|
||||||
block-declaration := opaque-enum-declaration
|
block-declaration := opaque-enum-declaration
|
||||||
nodeclspec-function-declaration := declarator ;
|
nodeclspec-function-declaration := function-declarator ;
|
||||||
alias-declaration := USING IDENTIFIER = defining-type-id ;
|
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 ;
|
||||||
simple-declaration := decl-specifier-seq ref-qualifier_opt [ identifier-list ] initializer ;
|
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 )
|
placeholder-type-specifier := type-constraint_opt DECLTYPE ( AUTO )
|
||||||
init-declarator-list := init-declarator
|
init-declarator-list := init-declarator
|
||||||
init-declarator-list := init-declarator-list , init-declarator
|
init-declarator-list := init-declarator-list , init-declarator
|
||||||
init-declarator := declarator initializer_opt
|
#! The standard grammar allows:
|
||||||
init-declarator := declarator requires-clause
|
#! 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 := ptr-declarator
|
||||||
declarator := noptr-declarator parameters-and-qualifiers trailing-return-type
|
declarator := noptr-declarator parameters-and-qualifiers trailing-return-type
|
||||||
ptr-declarator := noptr-declarator
|
ptr-declarator := noptr-declarator
|
||||||
|
@ -472,8 +483,8 @@ designator := [ expression ]
|
||||||
expr-or-braced-init-list := expression
|
expr-or-braced-init-list := expression
|
||||||
expr-or-braced-init-list := braced-init-list
|
expr-or-braced-init-list := braced-init-list
|
||||||
# dcl.fct
|
# dcl.fct
|
||||||
function-definition := decl-specifier-seq_opt declarator virt-specifier-seq_opt function-body
|
function-definition := decl-specifier-seq_opt function-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 requires-clause function-body
|
||||||
function-body := ctor-initializer_opt compound-statement
|
function-body := ctor-initializer_opt compound-statement
|
||||||
function-body := function-try-block
|
function-body := function-try-block
|
||||||
function-body := = DEFAULT ;
|
function-body := = DEFAULT ;
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// The standard grammar allows an init-list with any declarator, including
|
// The standard grammar allows an init-list with any declarator, including
|
||||||
// a function declarator. This creates an ambiguity where a function-definition
|
// a function declarator. This creates an ambiguity where a function-definition
|
||||||
// is misparsed as a simple-declaration.
|
// is misparsed as a simple-declaration.
|
||||||
// FIXME: eliminate this false parse.
|
|
||||||
// XFAIL: *
|
|
||||||
|
|
||||||
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
|
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
|
||||||
void s(){};
|
void s(){};
|
||||||
// CHECK-NOT: simple-declaration
|
// CHECK-NOT: simple-declaration
|
||||||
// CHECK: function-definition := decl-specifier-seq declarator
|
// CHECK: function-definition := decl-specifier-seq function-declarator function-body
|
||||||
// function-body CHECK-NOT: simple-declaration
|
// CHECK-NOT: simple-declaration
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// The standard grammar allows an function-body to use any declarator, including
|
// The standard grammar allows an function-body to use any declarator, including
|
||||||
// a non-function declarator. This creates an ambiguity where a
|
// a non-function declarator. This creates an ambiguity where a
|
||||||
// simple-declaration is misparsed as a function-definition.
|
// 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
|
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
|
||||||
void (*s)(){};
|
void (*s)(){};
|
||||||
// CHECK-NOT: function-definition
|
// CHECK-NOT: function-definition
|
||||||
// CHECK: init-declarator := declarator initializer
|
// CHECK: init-declarator := non-function-declarator initializer
|
||||||
// CHECK-NOT: function-definition
|
// CHECK-NOT: function-definition
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
|
// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s
|
||||||
void foo(complete garbage???) {}
|
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: ├─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: │ ├─noptr-declarator~IDENTIFIER := tok[1]
|
||||||
// CHECK-NEXT: │ └─parameters-and-qualifiers := ( parameter-declaration-clause [recover=Brackets] )
|
// CHECK-NEXT: │ └─parameters-and-qualifiers := ( parameter-declaration-clause [recover=Brackets] )
|
||||||
// CHECK-NEXT: │ ├─( := tok[2]
|
// CHECK-NEXT: │ ├─( := tok[2]
|
||||||
|
|
|
@ -3,7 +3,7 @@ auto x = { complete garbage };
|
||||||
// CHECK: translation-unit~simple-declaration
|
// CHECK: translation-unit~simple-declaration
|
||||||
// CHECK-NEXT: ├─decl-specifier-seq~AUTO := tok[0]
|
// CHECK-NEXT: ├─decl-specifier-seq~AUTO := tok[0]
|
||||||
// CHECK-NEXT: ├─init-declarator-list~init-declarator
|
// 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: │ └─initializer~brace-or-equal-initializer
|
||||||
// CHECK-NEXT: │ ├─= := tok[2]
|
// CHECK-NEXT: │ ├─= := tok[2]
|
||||||
// CHECK-NEXT: │ └─initializer-clause~braced-init-list
|
// 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() {
|
void foo() {
|
||||||
T* a; // a multiply expression or a pointer declaration?
|
T* a; // a multiply expression or a pointer declaration?
|
||||||
|
|
Loading…
Reference in New Issue