efriedma created this revision. efriedma added a reviewer: rsmith. Herald added a project: clang.
When we see something like `i<i`, we try to check whether the second "i" refers to a type. However, when we do this, we can end up creating an expression in the wrong context: the "<" has different parse priority if it's actually a relational operator. To fix the issue, just remove the check. This makes diagnostics slightly worse, but avoids the crash. I'm not really happy with this, but I don't see another way to fix this without implementing a giant refactoring. Fixes https://bugs.llvm.org/show_bug.cgi?id=43080 (but not the issues currently marked as "duplicate"; I haven't dug deeply into the causes of those issues). Repository: rC Clang https://reviews.llvm.org/D68849 Files: lib/Parse/ParseTemplate.cpp test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp test/CodeGenCXX/odr-use.cpp test/SemaCXX/cxx1y-variable-templates_top_level.cpp test/SemaTemplate/typo-template-name.cpp
Index: test/SemaTemplate/typo-template-name.cpp =================================================================== --- test/SemaTemplate/typo-template-name.cpp +++ test/SemaTemplate/typo-template-name.cpp @@ -5,14 +5,14 @@ void typo_first_a(); // expected-note {{found}} template<typename T> void typo_first_b(); // expected-note 2{{declared here}} } - void testA() { A::typo_first_a<int>(); } // expected-error {{'typo_first_a' does not name a template but is followed by template arguments; did you mean 'typo_first_b'?}} + void testA() { A::typo_first_a<int>(); } // expected-error {{expected '(' for function-style cast or type construction}} expected-error {{'typo_first_a' does not name a template but is followed by template arguments; did you mean 'typo_first_b'?}} namespace B { void typo_first_b(); // expected-note {{found}} } - void testB() { B::typo_first_b<int>(); } // expected-error {{'typo_first_b' does not name a template but is followed by template arguments; did you mean 'A::typo_first_b'?}} + void testB() { B::typo_first_b<int>(); } // expected-error {{expected '(' for function-style cast or type construction}} expected-error {{'typo_first_b' does not name a template but is followed by template arguments; did you mean 'A::typo_first_b'?}} - struct Base { + struct Base { // expected-note {{declared here}} template<typename T> static void foo(); // expected-note 4{{declared here}} int n; }; @@ -20,19 +20,19 @@ void foo(); // expected-note {{found}} }; // We probably don't want to suggest correcting to .Base::foo<int> - void testMember() { Derived().foo<int>(); } // expected-error-re {{does not name a template but is followed by template arguments{{$}}}} + void testMember() { Derived().foo<int>(); } // expected-error {{expected '(' for function-style cast or type construction}} expected-error-re {{does not name a template but is followed by template arguments{{$}}}} struct Derived2 : Base { void goo(); // expected-note {{found}} }; - void testMember2() { Derived2().goo<int>(); } // expected-error {{member 'goo' of 'InExpr::Derived2' is not a template; did you mean 'foo'?}} + void testMember2() { Derived2().goo<int>(); } // expected-error {{expected '(' for function-style cast or type construction}} expected-error {{member 'goo' of 'InExpr::Derived2' is not a template; did you mean 'foo'?}} void no_correction() { int foo; // expected-note 3{{found}} - foo<int>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}} + foo<int>(); // expected-error {{expected '(' for function-style cast or type construction}} expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}} foo<>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}} - foo<Base *>(); // expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}} + foo<Base *>(); // expected-error {{'Base' does not refer to a value}} expected-error {{expected expression}} expected-error {{'foo' does not name a template but is followed by template arguments; did you mean 'Base::foo'?}} // These are valid expressions. foo<foo; // expected-warning {{self-comparison}} Index: test/SemaCXX/cxx1y-variable-templates_top_level.cpp =================================================================== --- test/SemaCXX/cxx1y-variable-templates_top_level.cpp +++ test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -9,7 +9,7 @@ #endif template<typename T> -T pi = T(3.1415926535897932385); // expected-note 2{{declared here}} +T pi = T(3.1415926535897932385); // expected-note {{declared here}} template<typename T> CONST T cpi = T(3.1415926535897932385); // expected-note {{template is declared here}} @@ -58,9 +58,9 @@ namespace shadow { void foo() { int ipi0 = pi<int>; - int pi; // expected-note {{found}} + int pi; int a = pi; - int ipi = pi<int>; // expected-error {{'pi' does not name a template but is followed by template arguments; did you mean '::pi'?}} + int ipi = pi<int>; // expected-error {{expected '(' for function-style cast or type construction}} expected-error {{expected expression}} } } Index: test/CodeGenCXX/odr-use.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/odr-use.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -triple x86_64-linux-gnu %s | FileCheck %s --check-prefixes=CHECK + +// Make sure this doesn't crash, and produces reasonable output +// CHECK: icmp ult i64 4, +int f(int i) { return sizeof i<i; } Index: test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp =================================================================== --- test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp +++ test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp @@ -26,19 +26,13 @@ } namespace std_example { - int h; // expected-note {{non-template declaration}} + int h; void g(); -#if __cplusplus <= 201703L - // expected-note@-2 {{non-template declaration}} -#endif namespace N { struct A {}; template<class T> int f(T); template<class T> int g(T); -#if __cplusplus <= 201703L - // expected-note@-2 {{here}} -#endif - template<class T> int h(T); // expected-note {{here}} + template<class T> int h(T); } int x = f<N::A>(N::A()); @@ -47,9 +41,9 @@ #endif int y = g<N::A>(N::A()); #if __cplusplus <= 201703L - // expected-error@-2 {{'g' does not name a template but is followed by template arguments; did you mean 'N::g'?}} + // expected-error@-2 {{expected '(' for function-style cast or type construction}} #endif - int z = h<N::A>(N::A()); // expected-error {{'h' does not name a template but is followed by template arguments; did you mean 'N::h'?}} + int z = h<N::A>(N::A()); // expected-error {{expected '(' for function-style cast or type construction}} } namespace AnnexD_example { Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1609,22 +1609,6 @@ return; } - // If we have 'potential_template<type-id', assume it's supposed to be a - // template-name if there's a matching '>' later on. - { - // FIXME: Avoid the tentative parse when NextToken() can't begin a type. - TentativeParsingAction TPA(*this); - SourceLocation Less = ConsumeToken(); - if (isTypeIdUnambiguously() && - diagnoseUnknownTemplateId(PotentialTemplateName, Less)) { - TPA.Commit(); - // FIXME: Perform error recovery. - PotentialTemplateName = ExprError(); - return; - } - TPA.Revert(); - } - // Otherwise, remember that we saw this in case we see a potentially-matching // '>' token later on. AngleBracketTracker::Priority Priority =
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits