hokein updated this revision to Diff 447815. hokein added a comment. refine the patch: guard the "::" nested-name-specifier rule instead.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D130511/new/ https://reviews.llvm.org/D130511 Files: clang-tools-extra/pseudo/lib/cxx/CXX.cpp clang-tools-extra/pseudo/lib/cxx/cxx.bnf clang-tools-extra/pseudo/test/cxx/nested-name-specifier.cpp Index: clang-tools-extra/pseudo/test/cxx/nested-name-specifier.cpp =================================================================== --- /dev/null +++ clang-tools-extra/pseudo/test/cxx/nested-name-specifier.cpp @@ -0,0 +1,19 @@ +// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s + +// Verify that we don't form a complete `::` nested-name-specifier if there is +// an identifier preceding it. +Foo::Foo() {} // No "Foo ::Foo()" false parse +// CHECK: ├─declaration-seq~function-definition := function-declarator function-body +// CHECK-NEXT: │ ├─function-declarator~noptr-declarator := noptr-declarator parameters-and-qualifiers + +int ::x; +// CHECK: declaration~simple-declaration := decl-specifier-seq init-declarator-list ; +// CHECK-NEXT: ├─decl-specifier-seq~INT + +void test() { + X::Y::Z; // No false qualified-declarator parses "X ::Y::Z" and "X::Y ::Z". +// CHECK: statement-seq~statement := <ambiguous> +// CHECK: statement~expression-statement := expression ; +// CHECK: statement~simple-declaration := decl-specifier-seq ; +// CHECK-NOT: simple-declaration := decl-specifier-seq init-declarator-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 @@ -68,7 +68,7 @@ unqualified-id := ~ decltype-specifier unqualified-id := template-id qualified-id := nested-name-specifier TEMPLATE_opt unqualified-id -nested-name-specifier := :: +nested-name-specifier := :: [guard] nested-name-specifier := type-name :: nested-name-specifier := namespace-name :: nested-name-specifier := decltype-specifier :: 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 @@ -164,6 +164,12 @@ return P.Tokens.tokens()[P.LookaheadIndex].Kind != tok::kw_else; } +bool guardPreviousTokenNotIdentifier(const GuardParams &P) { + if (P.LookaheadIndex < 2) + return true; + return P.Tokens.tokens()[P.LookaheadIndex-2].Kind != tok::identifier; +} + // 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. // @@ -310,6 +316,14 @@ selection_statement_0if_1constexpr_2l_paren_3condition_4r_paren_5statement, guardNextTokenNotElse}, + // Implement C++ [basic.lookup.qual.general]: + // If a name, template-id, or decltype-specifier is followed by a + // ::, it shall designate a namespace, class, enumeration, or + // dependent type, and the :: is never interpreted as a complete + // nested-name-specifier. + {(RuleID)Rule::nested_name_specifier_0coloncolon, + guardPreviousTokenNotIdentifier}, + // The grammar distinguishes (only) user-defined vs plain string literals, // where the clang lexer distinguishes (only) encoding types. {(RuleID)Rule::user_defined_string_literal_chunk_0string_literal,
Index: clang-tools-extra/pseudo/test/cxx/nested-name-specifier.cpp =================================================================== --- /dev/null +++ clang-tools-extra/pseudo/test/cxx/nested-name-specifier.cpp @@ -0,0 +1,19 @@ +// RUN: clang-pseudo -grammar=cxx -source=%s --print-forest | FileCheck %s + +// Verify that we don't form a complete `::` nested-name-specifier if there is +// an identifier preceding it. +Foo::Foo() {} // No "Foo ::Foo()" false parse +// CHECK: ââdeclaration-seq~function-definition := function-declarator function-body +// CHECK-NEXT: â ââfunction-declarator~noptr-declarator := noptr-declarator parameters-and-qualifiers + +int ::x; +// CHECK: declaration~simple-declaration := decl-specifier-seq init-declarator-list ; +// CHECK-NEXT: ââdecl-specifier-seq~INT + +void test() { + X::Y::Z; // No false qualified-declarator parses "X ::Y::Z" and "X::Y ::Z". +// CHECK: statement-seq~statement := <ambiguous> +// CHECK: statement~expression-statement := expression ; +// CHECK: statement~simple-declaration := decl-specifier-seq ; +// CHECK-NOT: simple-declaration := decl-specifier-seq init-declarator-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 @@ -68,7 +68,7 @@ unqualified-id := ~ decltype-specifier unqualified-id := template-id qualified-id := nested-name-specifier TEMPLATE_opt unqualified-id -nested-name-specifier := :: +nested-name-specifier := :: [guard] nested-name-specifier := type-name :: nested-name-specifier := namespace-name :: nested-name-specifier := decltype-specifier :: 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 @@ -164,6 +164,12 @@ return P.Tokens.tokens()[P.LookaheadIndex].Kind != tok::kw_else; } +bool guardPreviousTokenNotIdentifier(const GuardParams &P) { + if (P.LookaheadIndex < 2) + return true; + return P.Tokens.tokens()[P.LookaheadIndex-2].Kind != tok::identifier; +} + // 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. // @@ -310,6 +316,14 @@ selection_statement_0if_1constexpr_2l_paren_3condition_4r_paren_5statement, guardNextTokenNotElse}, + // Implement C++ [basic.lookup.qual.general]: + // If a name, template-id, or decltype-specifier is followed by a + // â::â, it shall designate a namespace, class, enumeration, or + // dependent type, and the â::â is never interpreted as a complete + // nested-name-specifier. + {(RuleID)Rule::nested_name_specifier_0coloncolon, + guardPreviousTokenNotIdentifier}, + // The grammar distinguishes (only) user-defined vs plain string literals, // where the clang lexer distinguishes (only) encoding types. {(RuleID)Rule::user_defined_string_literal_chunk_0string_literal,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits