From patchwork Sat Feb 20 22:22:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 585707 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 7992D140B0F for ; Sun, 21 Feb 2016 09:23:14 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=ec6VNTF5; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=OL7i41vbw/ND AXRH35wE5lEK8w59MhahQWUV6ZDkGhnKmqDutgJDRkugC8yuJPJTxJephs5C/TYE 16O/Mo2MPD1XyuzMsJPJRpKADqTWWx2+TiJvfKYcBtkkFTkJyhYqs0yggL/qJouP nMANISmOHXuGbZcaUIqyCeMGW3Re1HA= 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:from :to:cc:subject:date:message-id; s=default; bh=d5pSsVV4eysverlnJY nCK3HuzNI=; b=ec6VNTF59kkA9zSvr5px/f0Z00jhnn50++4sHpVwm4d0Vw6Tyd VDBOjJceUpVRrcMKaWIF989Erbip8JIU88YD873DhqtamQIu2U6yKKjjlY3FJY+E UB2sWjvIlpyzbfB/DdcNKcMKvg2caC25De3rRB0Ob9SdmnMgl4gNsvLH8= Received: (qmail 14426 invoked by alias); 20 Feb 2016 22:23:06 -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 14411 invoked by uid 89); 20 Feb 2016 22:23:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=MODIFY_EXPR, modify_expr, indirect_ref, INDIRECT_REF X-HELO: mail-qg0-f50.google.com Received: from mail-qg0-f50.google.com (HELO mail-qg0-f50.google.com) (209.85.192.50) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sat, 20 Feb 2016 22:23:04 +0000 Received: by mail-qg0-f50.google.com with SMTP id y89so87480206qge.2 for ; Sat, 20 Feb 2016 14:23:03 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=N7V5IBPxbTv94VNiRse2VRZKnTh+rOpuwtBNyvCJVQ4=; b=jL6cKP0zA0CeZtVCzHshKWZ9l1BpEjPcNhmG0Zen/wSoULPascOQhtIoCiBjzHwV83 o/Z9u3Y0CREcLQ5s87Bcwiy1PaooN4cYoJ/dQvT6lLX4OXVXviqOWPUml+PV643IDCYD YTAUDChFUVOVpRM3R9ED6DEANMtN/YfkxBWcU4BVMMLHgSXjKAttHTOT9ivyFsgWt6Ez YLmrbdcZRQ/kIerX+0J+9Aga7KKnEV8RKvn/ntp6/1TogSAN6jLX0EW439gxb0H0jA+P XgBzEJs11FJJ8TsP4zcVdZ+YdxH7bI8o9d+aLlvtrhd89+Df7d3w0r2MmRHGAmHzLQaX QGPw== X-Gm-Message-State: AG10YORRDJuNdIHVyA3bmQ1spjDC6LummgyKwu2x6Uet7nFKv4CPO6ZBBbGUDZiddMkj8w== X-Received: by 10.140.242.16 with SMTP id n16mr27351830qhc.2.1456006981895; Sat, 20 Feb 2016 14:23:01 -0800 (PST) Received: from localhost.localdomain (ool-4353abbc.dyn.optonline.net. [67.83.171.188]) by smtp.gmail.com with ESMTPSA id d64sm3679869qgd.9.2016.02.20.14.23.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 20 Feb 2016 14:23:00 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com, Patrick Palka Subject: [PATCH] Fix PR c++/69694 (non-dependent MODOP_EXPR with NULL type) Date: Sat, 20 Feb 2016 17:22:54 -0500 Message-Id: <1456006974-7430-1-git-send-email-patrick@parcs.ath.cx> The problem here is that when processing_template_decl, the non-compound MODOP_EXPRs we build (i.e. a = b and not a += b) are given a NULL TREE_TYPE even if none of its operands are dependent. This causes decltypes such as "decltype (a = b)" (where a and b are not dependent) to fail to get resolved to a concrete type since the MODOP_EXPR within is considered to be dependent according to instantiation_dependent_expression_p. And in the case of decltype65.C this causes partial-specialization selection to malfunction since the template parameter type "void_t" never gets resolved to "void". This patch fixes this issue by adjusting build_x_modify_expr to give non-compound non-dependent MODOP_EXPRs an accurate non-NULL TREE_TYPE. To do this we have to first process the assignment at template processing time using cp_build_modify_expr. This means we will now diagnose invalid assignments at template-processing time, necessitating some minor adjustments to the testsuite. The changes to the test suite are trivial except for the change to unary2.C. Here, whereas before we were always failing to diagnose at template processing time the invalid assignment -n = 0 (whose LHS is not an lvalue), after this patch we now fail to diagnose this invalid assignment only with c++98. This is because lvalue_kind treats NON_DEPENDENT_EXPRs differently depending on the cxx_dialect: case NON_DEPENDENT_EXPR: /* We just return clk_ordinary for NON_DEPENDENT_EXPR in C++98, but in C++11 lvalues don't bind to rvalue references, so we need to work harder to avoid bogus errors (c++/44870). */ if (cxx_dialect < cxx11) return clk_ordinary; else return lvalue_kind (TREE_OPERAND (ref, 0)); So in c++98 mode any NON_DEPENDENT_EXPR is considered to be a valid LHS of an assignment even if the underlying expression is not actually an lvalue. Removing this special case is not completely trivial. Bootstrap + regtest in progress on x86_64-pc-linux-gnu, will also test against Boost. Does this look OK if testing passes? gcc/cp/ChangeLog: PR c++/69694 * semantics.c (finish_paranthesized_expr): Set the TREE_NO_WARNING flag on MODOP_EXPRs that are wrapped in an implicit INDIRECT_REF. * typeck.c (build_x_modify_expr): Give the middle operand of the resulting MODOP_EXPR a dummy non-NULL type. When MODIFYCODE is NOP_EXPR and the operands are not dependent, don't exit early and instead process the expression with cp_build_modify_expr. Assert that the return value of build_new_op is non-NULL. gcc/testsuite/ChangeLog: PR c++/69694 * g++.dg/cpp0x/decltype64.C: New test. * g++.dg/cpp0x/decltype65.C: New test. * g++.dg/expr/unary2.C: The XFAILs no longer fail on c++11 or later, only with c++98. * g++.dg/cpp0x/error2.C: Adjust expected error message. * g++.dg/ext/fixed1.C: Likewise. * g++.dg/template/error35.C: Likewise. * g++.dg/template/init7.C: Likewise. --- gcc/cp/semantics.c | 7 +++++++ gcc/cp/typeck.c | 30 +++++++++++++++++++++--------- gcc/testsuite/g++.dg/cpp0x/decltype64.C | 30 ++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/decltype65.C | 24 ++++++++++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/error2.C | 2 +- gcc/testsuite/g++.dg/expr/unary2.C | 4 ++-- gcc/testsuite/g++.dg/ext/fixed1.C | 4 ++-- gcc/testsuite/g++.dg/template/error35.C | 2 +- gcc/testsuite/g++.dg/template/init7.C | 3 ++- 9 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype64.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype65.C diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 4bbc698..20f263f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1704,6 +1704,13 @@ finish_parenthesized_expr (cp_expr expr) /* This inhibits warnings in c_common_truthvalue_conversion. */ TREE_NO_WARNING (expr) = 1; + /* This inhibits -Wparentheses warnings for parenthesized non-dependent + MODOP_EXPRs, which are wrapped in an implicit INDIRECT_REF. */ + if (processing_template_decl + && REFERENCE_REF_P (expr) + && TREE_CODE (TREE_OPERAND (expr, 0)) == MODOP_EXPR) + TREE_NO_WARNING (TREE_OPERAND (expr, 0)) = 1; + if (TREE_CODE (expr) == OFFSET_REF || TREE_CODE (expr) == SCOPE_REF) /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 5145879..3da6ea1 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7869,26 +7869,39 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree orig_lhs = lhs; tree orig_rhs = rhs; tree overload = NULL_TREE; - tree op = build_nt (modifycode, NULL_TREE, NULL_TREE); + /* Give this middle operand of the resulting MODOP_EXPR a dummy non-NULL type + so that instantiation_dependent_expression_p won't later consider an + otherwise non-dependent MODOP_EXPR to be dependent. */ + tree op = build_min (modifycode, void_type_node, NULL_TREE, NULL_TREE); if (processing_template_decl) { - if (modifycode == NOP_EXPR - || type_dependent_expression_p (lhs) + if (type_dependent_expression_p (lhs) || type_dependent_expression_p (rhs)) - return build_min_nt_loc (loc, MODOP_EXPR, lhs, - build_min_nt_loc (loc, modifycode, NULL_TREE, - NULL_TREE), rhs); + return build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs); lhs = build_non_dependent_expr (lhs); rhs = build_non_dependent_expr (rhs); } - if (modifycode != NOP_EXPR) + if (modifycode == NOP_EXPR) + { + tree result = cp_build_modify_expr (lhs, modifycode, rhs, complain); + + if (processing_template_decl) + return build_min_non_dep (MODOP_EXPR, result, orig_lhs, op, orig_rhs); + + return result; + } + else { tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs, op, &overload, complain); - if (rval) + + /* This shouldn't happen. */ + if (rval == NULL_TREE) + gcc_unreachable (); + else { if (rval == error_mark_node) return rval; @@ -7905,7 +7918,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, return rval; } } - return cp_build_modify_expr (lhs, modifycode, rhs, complain); } /* Helper function for get_delta_difference which assumes FROM is a base diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype64.C b/gcc/testsuite/g++.dg/cpp0x/decltype64.C new file mode 100644 index 0000000..9ddd1c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype64.C @@ -0,0 +1,30 @@ +// PR c++/69694 +// { dg-do compile { target c++11 } } + +// n3911: TransformationTrait Alias `void_t` +template struct make_void { using type = void; }; +template using void_t = typename make_void::type; + +// std::declval +void*& declval_void(); + +template struct Fun; +template + struct Fun +{ + void fun(); +}; +template + struct Fun> + : Fun +{ +}; + +struct Tag { static constexpr void* name = 0; }; + +template void a() +{ + Fun{}.fun(); +} + +void b() { a(); } diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype65.C b/gcc/testsuite/g++.dg/cpp0x/decltype65.C new file mode 100644 index 0000000..95fe0f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype65.C @@ -0,0 +1,24 @@ +// PR c++/69694 +// This is a reduced version of decltype64.C. +// { dg-do compile { target c++11 } } + +template using void_t = void; + +extern void *declval_void; + +template struct Fun { }; + +template +struct Fun> +{ + void fun(); +}; + +struct Tag { static constexpr void* name = 0; }; + +template void a() +{ + Fun{}.fun(); +} + +void b() { a(); } diff --git a/gcc/testsuite/g++.dg/cpp0x/error2.C b/gcc/testsuite/g++.dg/cpp0x/error2.C index e6af294..ec58c9c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/error2.C +++ b/gcc/testsuite/g++.dg/cpp0x/error2.C @@ -5,5 +5,5 @@ template int foo(); template void bar(F f) { - f((foo<0>()=0)...); // { dg-error "pattern '\\(foo\\<0\\>\\)\\(\\)=0'" } + f((foo<0>()=0)...); // { dg-error "lvalue|pattern '\\(foo\\<0\\>\\)\\(\\)=0'" } } diff --git a/gcc/testsuite/g++.dg/expr/unary2.C b/gcc/testsuite/g++.dg/expr/unary2.C index 8418815..80bfd7d 100644 --- a/gcc/testsuite/g++.dg/expr/unary2.C +++ b/gcc/testsuite/g++.dg/expr/unary2.C @@ -15,6 +15,6 @@ void f(void) template void g(void) { - -n = 0; // { dg-error "lvalue" "" { xfail *-*-* } } - +n = 0; // { dg-error "lvalue" "" { xfail *-*-* } } + -n = 0; // { dg-error "lvalue" "" { xfail c++98_only } } + +n = 0; // { dg-error "lvalue" "" { xfail c++98_only } } } diff --git a/gcc/testsuite/g++.dg/ext/fixed1.C b/gcc/testsuite/g++.dg/ext/fixed1.C index 5a479d6..4fcea0f 100644 --- a/gcc/testsuite/g++.dg/ext/fixed1.C +++ b/gcc/testsuite/g++.dg/ext/fixed1.C @@ -3,6 +3,6 @@ template struct A {}; -template struct B : A {}; // { dg-error "not supported" } +template struct B : A {}; // { dg-error "convert|not supported" } -template struct C : A {}; // { dg-error "not supported" } +template struct C : A {}; // { dg-error "convert|not supported" } diff --git a/gcc/testsuite/g++.dg/template/error35.C b/gcc/testsuite/g++.dg/template/error35.C index d52e599..3b11fb7 100644 --- a/gcc/testsuite/g++.dg/template/error35.C +++ b/gcc/testsuite/g++.dg/template/error35.C @@ -1,3 +1,3 @@ // PR c++/33494 -template void foo(int(*f=0)()); // { dg-error "declared void|scope|erroneous-expression" } +template void foo(int(*f=0)()); // { dg-error "declared void|scope|expression" } diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C index bb26c8f..3410c01 100644 --- a/gcc/testsuite/g++.dg/template/init7.C +++ b/gcc/testsuite/g++.dg/template/init7.C @@ -6,4 +6,5 @@ template struct A static const int i=0; }; -template const int A::i = 0=0; /* { dg-error "duplicate initialization" } */ +template +const int A::i = 0=0; // { dg-error "duplicate initialization|lvalue" }