From patchwork Mon Aug 11 18:01:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Carlini X-Patchwork-Id: 379112 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 2C98D140142 for ; Tue, 12 Aug 2014 04:01:29 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=IlYTp6IH0EpkRttj14vQ0j68SWHFpipL5q4iqQKsCKa Zfzb9/lKa7mCsn999wEdsYP5iYN4EIWqrnlnMvDjvtSkwz05cFNdpXRpDO2fNdBN g+uags+MW8niZbrLD0+lll2h7w7vUeXJ+y/pjcO+Iygt5t9tOOxvZk5LH0zjXMN4 = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=ejR1e4eoq5MHjrVQACtW+9fANi0=; b=KxU2CqoEecfau4ZMj rTtDpNbKUtkEX1txXKLCzlE4JwsbNByLcTVo4zoi9RymZiAiT0Cmglqkmpp1yavZ mgE0SxFFFljkTbFzzI2XM7jIRA4PBr1+S8kOnoJJbmaulew8PxIj9R1VxRYwh8Nw ITAfA9IlXliElh6QmhHrK8Vqzc= Received: (qmail 6510 invoked by alias); 11 Aug 2014 18:01:22 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 6496 invoked by uid 89); 11 Aug 2014 18:01:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.6 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: aserp1040.oracle.com Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Mon, 11 Aug 2014 18:01:20 +0000 Received: from acsinet22.oracle.com (acsinet22.oracle.com [141.146.126.238]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id s7BI1H3V017496 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 11 Aug 2014 18:01:17 GMT Received: from aserz7022.oracle.com (aserz7022.oracle.com [141.146.126.231]) by acsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s7BI1Geb003748 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 11 Aug 2014 18:01:16 GMT Received: from abhmp0002.oracle.com (abhmp0002.oracle.com [141.146.116.8]) by aserz7022.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id s7BI1GNo003735; Mon, 11 Aug 2014 18:01:16 GMT Received: from [192.168.1.4] (/79.21.176.181) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 11 Aug 2014 11:01:15 -0700 Message-ID: <53E904E9.3030503@oracle.com> Date: Mon, 11 Aug 2014 20:01:13 +0200 From: Paolo Carlini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.7.0 MIME-Version: 1.0 To: "gcc-patches@gcc.gnu.org" CC: Jason Merrill Subject: [RFC/Patch] Latent issue in cp_parser_template_id X-IsSubscribed: yes Hi, while working on a patchlet for the simple c++/54377 I noticed a latent issue, which goes normally unnoticed because template/typename17.c uses the catch all dg-error "". The issue is that, whereas for C++98 we give a sensible error message, for C++11 only the late "last resort" check in cp_parser_init_declarator: /* If the decl specifiers were bad, issue an error now that we're sure this was intended to be a declarator. Then continue declaring the variable(s), as int, to try to cut down on further errors. */ if (decl_specifiers->any_specifiers_p && decl_specifiers->type == error_mark_node) { cp_parser_error (parser, "invalid type in declaration"); decl_specifiers->type = integer_type_node; } catches the problem in the typename17.C snippet. As far as I can see, the problem is due to the CPP_TEMPLATE_ID optimization in cp_parser_template_id, eg, if I disable it with an && 0 the error message for C++11 becomes identical to that for C++98. The reason is, with C++11, cp_parser_template_id is called first with none_type as tag_type, when the optimization mechanism triggers, and then again with typename_type, when normally cp_parser_template_id would return error_mark_node (it does in C++98) and instead succeeds, returns the already parsed BASELINK. At the moment my impression is that the CPP_TEMPLATE_ID optimization is rather fragile because in reality the parsing can succeed or not depending on the tag_type passes to cp_parser_template_id and the optimization doesn't see that. Thus, what to do? Something that works, is coping after the fact with the BASELINK in cp_parser_elaborated_type_specifier, this allows to have a sensible error message for typename17.C and passes testing (patchlet attached)... If you are curious why I care that much about this issue, I have been also playing with removing the "last resort" check above, which would avoid a lot of redundant lines in the error messages (which other front-end doesn't seem to ever emit). If I do that, after adjusting for the redundant error messages, there are *no* regressions in the testsuite, *besides* exactly typename17.C in C++11 mode... I'm attaching a complete wip patch which passes testing. Thanks! Paolo. /////////////////////// Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 213809) +++ gcc/cp/parser.c (working copy) @@ -15194,6 +15188,12 @@ cp_parser_elaborated_type_specifier (cp_parser* pa identifier. */ if (!template_p && !cp_parser_parse_definitely (parser)) ; + else if (tag_type == typename_type + && BASELINK_P (decl)) + { + cp_parser_diagnose_invalid_type_name (parser, decl, token->location); + type = error_mark_node; + } /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is in effect, then we must assume that, upon instantiation, the template will correspond to a class. */ @@ -16897,17 +16895,6 @@ cp_parser_init_declarator (cp_parser* parser, possibly be looking at any other construct. */ cp_parser_commit_to_tentative_parse (parser); - /* If the decl specifiers were bad, issue an error now that we're - sure this was intended to be a declarator. Then continue - declaring the variable(s), as int, to try to cut down on further - errors. */ - if (decl_specifiers->any_specifiers_p - && decl_specifiers->type == error_mark_node) - { - cp_parser_error (parser, "invalid type in declaration"); - decl_specifiers->type = integer_type_node; - } - /* Enter the newly declared entry in the symbol table. If we're processing a declaration in a class-specifier, we wait until after processing the initializer. */ Index: gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/alias-decl-4.C (working copy) @@ -11,4 +11,4 @@ template using B = typename A::U; // template struct A { typedef B U; }; -B b; // { dg-error "invalid type" } +B b; Index: gcc/testsuite/g++.dg/cpp0x/decltype2.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/decltype2.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/decltype2.C (working copy) @@ -45,7 +45,6 @@ int bar(int); CHECK_DECLTYPE(decltype(foo), int(char)); decltype(bar) z; // { dg-error "overload" "overload" } -// { dg-error "invalid type" "invalid" { target *-*-* } 47 } CHECK_DECLTYPE(decltype(&foo), int(*)(char)); CHECK_DECLTYPE(decltype(*&foo), int(&)(char)); Index: gcc/testsuite/g++.dg/cpp0x/decltype3.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/decltype3.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/decltype3.C (working copy) @@ -55,7 +55,7 @@ class B { CHECK_DECLTYPE(decltype(aa.*&A::a), int&); decltype(aa.*&A::b) zz; // { dg-error "cannot create pointer to reference member" "cannot" } -// { dg-error "invalid type" "invalid type" { target *-*-* } 57 } + CHECK_DECLTYPE(decltype(caa.*&A::a), const int&); class X { Index: gcc/testsuite/g++.dg/cpp0x/pr60249.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/pr60249.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/pr60249.C (working copy) @@ -2,5 +2,3 @@ // { dg-do compile { target c++11 } } decltype(""_) x; // { dg-error "unable to find string literal operator" } - -// { dg-error "invalid type in declaration before" "invalid" { target *-*-* } 4 } Index: gcc/testsuite/g++.dg/cpp0x/variadic-ex10.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/variadic-ex10.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/variadic-ex10.C (working copy) @@ -6,4 +6,3 @@ Tuple t1; // Types contains one argument: int Tuple t2; // Types contains two arguments: int and float Tuple<0> error; // { dg-error "mismatch" "mismatch" } // { dg-message "expected a type" "expected a type" { target *-*-* } 7 } -// { dg-error "in declaration" "in declaration" { target *-*-* } 7 } Index: gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/variadic-ex14.C (working copy) @@ -10,10 +10,8 @@ template class Q> class Y { /* X xA; // okay X xB; // { dg-error "mismatch" "mismatch" } // { dg-message "expected a template" "expected" { target *-*-* } 11 } -// { dg-error "invalid type" "invalid" { target *-*-* } 11 } X xC; // { dg-error "mismatch" "mismatch" } -// { dg-message "expected a template" "expected" { target *-*-* } 14 } -// { dg-error "invalid type" "invalid" { target *-*-* } 14 } +// { dg-message "expected a template" "expected" { target *-*-* } 13 } Y yA; Y yB; Y yC; // okay Index: gcc/testsuite/g++.dg/cpp0x/variadic2.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/variadic2.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/variadic2.C (working copy) @@ -9,7 +9,6 @@ template bad; // { dg-error "2 or more" "2 or more" } -// { dg-error "invalid type" "invalid type" { target *-*-* } 11 } void f() { Index: gcc/testsuite/g++.dg/cpp0x/variadic74.C =================================================================== --- gcc/testsuite/g++.dg/cpp0x/variadic74.C (revision 213809) +++ gcc/testsuite/g++.dg/cpp0x/variadic74.C (working copy) @@ -20,9 +20,7 @@ A::X<&i, &f> apple1; B::X<&i, &f> banana1; A::X<&i> apple2; // { dg-error "wrong number of template arguments" "wrong number" } -// { dg-error "invalid type" "invalid" { target *-*-* } 22 } A::X<&i, &f, &f> apple3; // { dg-error "wrong number of template arguments" "wrong number" } -// { dg-error "invalid type" "invalid" { target *-*-* } 24 } A apple4; // { dg-prune-output "provided for" } Index: gcc/testsuite/g++.dg/parse/error10.C =================================================================== --- gcc/testsuite/g++.dg/parse/error10.C (revision 213809) +++ gcc/testsuite/g++.dg/parse/error10.C (working copy) @@ -14,6 +14,4 @@ template void foo() enum typename A::E e4; } -// Here, columns nums are not very accurate either. Still acceptable though -// { dg-error "30:invalid type in declaration before ';' token" "invalid" { target *-*-* } 14 } -// { dg-error "30:two or more data types in declaration of 'e4'" "2 or more" { target *-*-* } 14 } +// { dg-error "28:two or more data types in declaration of 'e4'" "2 or more" { target *-*-* } 14 } Index: gcc/testsuite/g++.dg/parse/error15.C =================================================================== --- gcc/testsuite/g++.dg/parse/error15.C (revision 213809) +++ gcc/testsuite/g++.dg/parse/error15.C (working copy) @@ -16,7 +16,6 @@ N::C::INVALID f4; // { dg-error "7:'INVALID' i N::K f6; // { dg-error "4:'K' in namespace 'N' does not name a type" } typename N::A f7; // { dg-error "13:invalid use of template-name 'N::A' without an argument list" "13" { target *-*-* } 17 } -// { dg-error "17:invalid type in declaration before ';' token" "17" { target *-*-* } 17 } struct B { @@ -25,7 +24,7 @@ struct B N::C::INVALID f4; // { dg-error "9:'INVALID' in 'struct N::C' does not name a type" } N::K f6; // { dg-error "6:'K' in namespace 'N' does not name a type" } typename N::A f7; -// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } 27 } +// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } 26 } }; template Index: gcc/testsuite/g++.dg/parse/error2.C =================================================================== --- gcc/testsuite/g++.dg/parse/error2.C (revision 213809) +++ gcc/testsuite/g++.dg/parse/error2.C (working copy) @@ -12,4 +12,3 @@ Foo f; // { dg-error "5:'int func.double. // { dg-error "10:'g' cannot appear in a constant-expression" "g" { target *-*-* } 11 } // { dg-error "11:a function call cannot appear in a constant-expression" "call" { target *-*-* } 11 } // { dg-error "12:template argument 1 is invalid" "invalid template argument" { target *-*-* } 11 } -// { dg-error "15:invalid type in declaration before ';' token" "invalid type" { target *-*-* } 11 } Index: gcc/testsuite/g++.dg/template/crash106.C =================================================================== --- gcc/testsuite/g++.dg/template/crash106.C (revision 213809) +++ gcc/testsuite/g++.dg/template/crash106.C (working copy) @@ -9,6 +9,6 @@ struct A template > struct B {}; // { dg-error "type|declared" } -B<> b; // { dg-error "type|declaration" } +B<> b; // { dg-message "non-type" } // { dg-prune-output "could not convert" } Index: gcc/testsuite/g++.dg/template/crash89.C =================================================================== --- gcc/testsuite/g++.dg/template/crash89.C (revision 213809) +++ gcc/testsuite/g++.dg/template/crash89.C (working copy) @@ -5,6 +5,4 @@ template struct A // { d typedef A B; }; -A a; // { dg-error "declaration" } - -// { dg-prune-output "template argument 2 is invalid" } +A a; // { dg-error "template argument 2 is invalid" } Index: gcc/testsuite/g++.dg/template/nontype7.C =================================================================== --- gcc/testsuite/g++.dg/template/nontype7.C (revision 213809) +++ gcc/testsuite/g++.dg/template/nontype7.C (working copy) @@ -10,6 +10,3 @@ char p[] = "Vivisectionist"; X x1; // { dg-error "string literal" } X x2; - -// { dg-bogus "" "additional errors" { xfail *-*-* } 11 } - Index: gcc/testsuite/g++.dg/template/void3.C =================================================================== --- gcc/testsuite/g++.dg/template/void3.C (revision 213809) +++ gcc/testsuite/g++.dg/template/void3.C (working copy) @@ -1,5 +1,5 @@ //PR c++/28637 template struct A {}; // { dg-error "not a valid type" } -A<0> a; // { dg-error "type" } +A<0> a; // { dg-message "non-type" } Index: gcc/testsuite/g++.dg/template/void7.C =================================================================== --- gcc/testsuite/g++.dg/template/void7.C (revision 213809) +++ gcc/testsuite/g++.dg/template/void7.C (working copy) @@ -5,4 +5,4 @@ template struct A // { dg-error "not static int i; }; -A<0> a; // { dg-error "invalid type|not a valid type" } +A<0> a; // { dg-message "non-type" } Index: libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/non_uint_neg.cc =================================================================== --- libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/non_uint_neg.cc (revision 213809) +++ libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/requirements/non_uint_neg.cc (working copy) @@ -21,8 +21,7 @@ // { dg-do compile } // { dg-options "-std=c++0x" } // { dg-require-cstdint "" } -// { dg-error "not a valid type" "" { target *-*-* } 32 } -// { dg-error "invalid type" "" { target *-*-* } 32 } +// { dg-error "not a valid type" "" { target *-*-* } 31 } // 26.4.3.1 class template linear_congruential_engine [rand.eng.lcong] // 26.4.2.2 Concept RandomNumberEngine [rand.concept.eng] @@ -30,4 +29,3 @@ #include std::linear_congruential_engine x; - Index: libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/linear_congruential/requirements/non_uint_neg.cc =================================================================== --- libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/linear_congruential/requirements/non_uint_neg.cc (revision 213809) +++ libstdc++-v3/testsuite/tr1/5_numerical_facilities/random/linear_congruential/requirements/non_uint_neg.cc (working copy) @@ -19,8 +19,7 @@ // { dg-do compile } // { dg-options "-D_GLIBCXX_CONCEPT_CHECKS" } -// { dg-error "not a valid type" "" { target *-*-* } 30 } -// { dg-error "invalid type" "" { target *-*-* } 30 } +// { dg-error "not a valid type" "" { target *-*-* } 29 } // 5.1.4.1 class template linear_congruential [tr.rand.eng.lcong] // 5.1.4.1 [4] @@ -28,4 +27,3 @@ #include std::tr1::linear_congruential x; - Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 213809) +++ gcc/cp/parser.c (working copy) @@ -15194,6 +15188,12 @@ cp_parser_elaborated_type_specifier (cp_parser* pa identifier. */ if (!template_p && !cp_parser_parse_definitely (parser)) ; + else if (tag_type == typename_type + && BASELINK_P (decl)) + { + cp_parser_diagnose_invalid_type_name (parser, decl, token->location); + type = error_mark_node; + } /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is in effect, then we must assume that, upon instantiation, the template will correspond to a class. */