From patchwork Fri Sep 1 14:34:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 137399 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c792:0:b0:3f2:4152:657d with SMTP id b18csp930389vqu; Fri, 1 Sep 2023 07:35:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHQm1wy0I9e6magjFE58l8Ca+vNzKVxjTXQQW3ZEKlpuCxqXRL4M8UEZCtbLKj3+2otWlwH X-Received: by 2002:a05:6402:2c4:b0:525:6772:1595 with SMTP id b4-20020a05640202c400b0052567721595mr2129691edx.6.1693578924816; Fri, 01 Sep 2023 07:35:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1693578924; cv=none; d=google.com; s=arc-20160816; b=skptojcvca8I9WV4pI4X0P9q7M1d2SFBnwrEyqnKyL9rxfts3jpzPGfHXChKfXI4J5 3pk7PYI1i2IlYcuU/WJOfTC11fES7BX0NAtvzmEIUFGPPw+m9bDZ6T7z0CR8MY2uTph/ RZdM1ajshYdAUyLJ/l07d3Jr5RorrWiC2MUzRIAdFRn7MD+B6zPxIzLWUCC62+ca39gx weD9CzHpMidiabnMq2u7MQQ7XONv68Ii1t8Jc/gPy1iFAzAtIhXGg0kFzh4VezBb/J52 BdF9GGSiZvvHifKOjM9jLNJXfQFAxch4P1H/2cVFeFliX1uIAkpJSpypPZmRvlwJz6Qe ludQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-disposition:in-reply-to:mime-version:references:message-id :subject:cc:to:date:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=i8s0jmvmZ+Bt965Ub8HtfaL6Q0dv1LpZxNz5kWOUWXY=; fh=0xZT+NBKSeH8qOu04/61f1ZGePpF4jF/gxp331YE14k=; b=pyp/ZIeOQt7ZnUJm6iW5AxgZZnrmuSN2RF/yfL3pTfKBanNZI4gEHeaFWjJoRH/WAm 6P+0eCTKhRBUrFoDXu7YjF7B8IHlFK319iO71lXvwD6raTAOcgCMe5FyOf2uzxwetusK 4XBvtrM8CV074b9k7/AnGd+VTIQgAILDhndkeIALPH45cqrpYdzeP6I2+FbczQQQiz/1 m+RAF+N5TX1PcQd2WoWJ3lRYdn+bv69ToFwMP+hch4VOs+unk3bYQj0hlYLu9f4Kjp+P ouEqd5zq1+x2vQR+Fw79z1gNmtSosKDjRS9kt60eHorr1xSy5qnxmvdt/UtIayUf43zc bIYg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=QqnzUFnY; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id f6-20020a056402160600b005221d280d58si2610925edv.101.2023.09.01.07.35.24 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 Sep 2023 07:35:24 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=QqnzUFnY; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 414AC385783F for ; Fri, 1 Sep 2023 14:35:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 414AC385783F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693578923; bh=i8s0jmvmZ+Bt965Ub8HtfaL6Q0dv1LpZxNz5kWOUWXY=; h=Date:To:Cc:Subject:References:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=QqnzUFnYrteumTuTJZoq6bp4pdGsQma0/kZipvKyYhyiRh8cLIYCXmfrZR1Jj+VzA zhiJKhbikwUhbIeNbda41RAkvMe9OStPLM3Noi+vpLUcj0gdGt+/5WV+8l2m5EWnBs ayX+OOimjlgrkl04IUe6rFrpj+0bUvAC9zbnZBCA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 495213858C2B for ; Fri, 1 Sep 2023 14:34:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 495213858C2B Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-690-rpF_SwtTMouy4cwEAPKg_w-1; Fri, 01 Sep 2023 10:34:31 -0400 X-MC-Unique: rpF_SwtTMouy4cwEAPKg_w-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 9E74A856DED for ; Fri, 1 Sep 2023 14:34:30 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.16]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 477A7D4781C; Fri, 1 Sep 2023 14:34:30 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 381EYSM82770843 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 1 Sep 2023 16:34:28 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 381EYSFm2770842; Fri, 1 Sep 2023 16:34:28 +0200 Date: Fri, 1 Sep 2023 16:34:28 +0200 To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++, v3: Diagnose [basic.scope.block]/2 violations even in compound-stmt of function-try-block [PR52953] Message-ID: References: MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1775846214535904118 X-GMAIL-MSGID: 1775846214535904118 On Fri, Sep 01, 2023 at 03:24:54PM +0200, Jakub Jelinek via Gcc-patches wrote: > So like this? > > It actually changes behaviour on the > void foo (int x) try {} catch (int x) {} case, where previously > this triggered the > || (TREE_CODE (old) == PARM_DECL > && (current_binding_level->kind == sk_catch > || current_binding_level->level_chain->kind == sk_catch) > && in_function_try_handler)) > { > auto_diagnostic_group d; > if (permerror (DECL_SOURCE_LOCATION (decl), > "redeclaration of %q#D", decl)) > inform (DECL_SOURCE_LOCATION (old), > "%q#D previously declared here", old); > diagnostics (note, just the current_binding_level->kind == sk_catch > case), while now it triggers already the earlier > if (b->kind == sk_function_parms) > { > error_at (DECL_SOURCE_LOCATION (decl), > "declaration of %q#D shadows a parameter", decl); > inform (DECL_SOURCE_LOCATION (old), > "%q#D previously declared here", old); > error. If you think it is important to differentiate that, > I guess I could guard the while (b->artificial) loop with say > + if (!in_function_try_handler > + || current_binding_level->kind != sk_catch) > while (b->artificial) > b = b->level_chain; > and adjust the 2 testcases. BTW, that in_function_try_handler case doesn't work correctly (before/after this patch), void foo (int x) try { } catch (int) { try { } catch (int x) { } try { } catch (int) { int x; } } (which is valid) is rejected, because || (TREE_CODE (old) == PARM_DECL && (current_binding_level->kind == sk_catch || current_binding_level->level_chain->kind == sk_catch) && in_function_try_handler)) is true but nothing verified that for the first case current_binding_level->level_chain->kind == sk_function_params (with perhaps artificial scopes in between and in the latter case with one extra level in between). Here is an untested variant of the patch which does diagnostics of the in_function_try_handler cases only if it is proven there are no intervening non-artificial scopes, but uses the old wording + permerror for that case like before. Another possibility would be to use permerror for that case but the "declaration of %q#D shadows a parameter" wording (then we'd need to adjust both testcases, each on one line). 2023-09-01 Jakub Jelinek PR c++/52953 * name-lookup.h (struct cp_binding_level): Add artificial bit-field. Formatting fixes. * name-lookup.cc (check_local_shadow): Skip artificial bindings when checking if parameter scope is parent scope. Don't special case FUNCTION_NEEDS_BODY_BLOCK. Diagnose the in_function_try_handler cases in the b->kind == sk_function_parms test, verify no non-artificial intervening scopes but use permerror for that case with different wording. Add missing auto_diagnostic_group. * decl.cc (begin_function_body): Set current_binding_level->artificial. * semantics.cc (begin_function_try_block): Likewise. * g++.dg/diagnostic/redeclaration-3.C: New test. Jakub --- gcc/cp/name-lookup.h.jj 2023-09-01 12:15:22.574619674 +0200 +++ gcc/cp/name-lookup.h 2023-09-01 16:11:47.838401045 +0200 @@ -292,11 +292,11 @@ struct GTY(()) cp_binding_level { only valid if KIND == SK_TEMPLATE_PARMS. */ BOOL_BITFIELD explicit_spec_p : 1; - /* true means make a BLOCK for this level regardless of all else. */ + /* True means make a BLOCK for this level regardless of all else. */ unsigned keep : 1; /* Nonzero if this level can safely have additional - cleanup-needing variables added to it. */ + cleanup-needing variables added to it. */ unsigned more_cleanups_ok : 1; unsigned have_cleanups : 1; @@ -308,9 +308,13 @@ struct GTY(()) cp_binding_level { unsigned defining_class_p : 1; /* True for SK_FUNCTION_PARMS of a requires-expression. */ - unsigned requires_expression: 1; + unsigned requires_expression : 1; - /* 22 bits left to fill a 32-bit word. */ + /* True for artificial blocks which should be ignored when finding + parent scope. */ + unsigned artificial : 1; + + /* 21 bits left to fill a 32-bit word. */ }; /* The binding level currently in effect. */ --- gcc/cp/name-lookup.cc.jj 2023-09-01 12:15:22.566619785 +0200 +++ gcc/cp/name-lookup.cc 2023-09-01 16:19:12.567335710 +0200 @@ -3146,18 +3146,34 @@ check_local_shadow (tree decl) them there. */ cp_binding_level *b = current_binding_level->level_chain; - if (FUNCTION_NEEDS_BODY_BLOCK (current_function_decl)) - /* Skip the ctor/dtor cleanup level. */ + if (in_function_try_handler && b->kind == sk_catch) + b = b->level_chain; + + /* Skip artificially added scopes which aren't present + in the C++ standard, e.g. for function-try-block or + ctor/dtor cleanups. */ + while (b->artificial) b = b->level_chain; /* [basic.scope.param] A parameter name shall not be redeclared in the outermost block of the function definition. */ if (b->kind == sk_function_parms) { - error_at (DECL_SOURCE_LOCATION (decl), - "declaration of %q#D shadows a parameter", decl); - inform (DECL_SOURCE_LOCATION (old), - "%q#D previously declared here", old); + auto_diagnostic_group d; + bool emit = true; + /* The [basic.scope.block]/(2.3) - handle of a function-try-block + used to emit a different diagnostics, preserve that. */ + if (in_function_try_handler + && (current_binding_level->kind == sk_catch + || current_binding_level->level_chain->kind == sk_catch)) + emit = permerror (DECL_SOURCE_LOCATION (decl), + "redeclaration of %q#D", decl); + else + error_at (DECL_SOURCE_LOCATION (decl), + "declaration of %q#D shadows a parameter", decl); + if (emit) + inform (DECL_SOURCE_LOCATION (old), + "%q#D previously declared here", old); return; } } @@ -3194,17 +3210,10 @@ check_local_shadow (tree decl) shall not be redeclared in the outermost block of the handler. 3.3.3/2: A parameter name shall not be redeclared (...) in the outermost block of any handler associated with a - function-try-block. - 3.4.1/15: The function parameter names shall not be redeclared - in the exception-declaration nor in the outermost block of a - handler for the function-try-block. */ - else if ((TREE_CODE (old) == VAR_DECL - && old_scope == current_binding_level->level_chain - && old_scope->kind == sk_catch) - || (TREE_CODE (old) == PARM_DECL - && (current_binding_level->kind == sk_catch - || current_binding_level->level_chain->kind == sk_catch) - && in_function_try_handler)) + function-try-block. */ + else if (TREE_CODE (old) == VAR_DECL + && old_scope == current_binding_level->level_chain + && old_scope->kind == sk_catch) { auto_diagnostic_group d; if (permerror (DECL_SOURCE_LOCATION (decl), --- gcc/cp/semantics.cc.jj 2023-09-01 12:15:22.650618611 +0200 +++ gcc/cp/semantics.cc 2023-09-01 16:11:47.844400963 +0200 @@ -1624,6 +1624,7 @@ begin_function_try_block (tree *compound /* This outer scope does not exist in the C++ standard, but we need a place to put __FUNCTION__ and similar variables. */ *compound_stmt = begin_compound_stmt (0); + current_binding_level->artificial = 1; r = begin_try_block (); FN_TRY_BLOCK_P (r) = 1; return r; --- gcc/cp/decl.cc.jj 2023-09-01 15:07:40.937661100 +0200 +++ gcc/cp/decl.cc 2023-09-01 16:11:47.842400991 +0200 @@ -18002,6 +18002,7 @@ begin_function_body (void) keep_next_level (true); tree stmt = begin_compound_stmt (BCS_FN_BODY); + current_binding_level->artificial = 1; if (processing_template_decl) /* Do nothing now. */; --- gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C.jj 2023-09-01 16:11:47.844400963 +0200 +++ gcc/testsuite/g++.dg/diagnostic/redeclaration-3.C 2023-09-01 16:24:21.865117426 +0200 @@ -0,0 +1,225 @@ +// PR c++/52953 +// { dg-do compile } +// { dg-options "-pedantic-errors -Wno-switch-unreachable" } + +void +foo (int x) // { dg-message "'int x' previously declared here" } +{ + int x; // { dg-error "declaration of 'int x' shadows a parameter" } +} + +void +bar (int x) // { dg-message "'int x' previously declared here" } +try +{ + int x; // { dg-error "declaration of 'int x' shadows a parameter" } +} +catch (...) +{ +} + +volatile int v; + +void +baz () +{ +#if __cplusplus >= 201103L + auto f = [] (int x) { int x; }; // { dg-error "declaration of 'int x' shadows a parameter" "" { target c++11 } } + // { dg-message "'int x' previously declared here" "" { target c++11 } .-1 } +#endif + if (int x = 1) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + } + if (int x = 0) // { dg-message "'int x' previously declared here" } + ; + else + { + int x; // { dg-error "redeclaration of 'int x'" } + } + if (int x = 1) // { dg-message "'int x' previously declared here" } + int x; // { dg-error "redeclaration of 'int x'" } + if (int x = 0) // { dg-message "'int x' previously declared here" } + ; + else + int x; // { dg-error "redeclaration of 'int x'" } + switch (int x = 1) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + default:; + } + switch (int x = 1) // { dg-message "'int x' previously declared here" } + int x; // { dg-error "redeclaration of 'int x'" } + while (int x = v) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + } + while (int x = v) // { dg-message "'int x' previously declared here" } + int x; // { dg-error "redeclaration of 'int x'" } + for (int x = v; x; ++x) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + } + for (int x = v; x; ++x) // { dg-message "'int x' previously declared here" } + int x; // { dg-error "redeclaration of 'int x'" } + for (; int x = v; ) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + } + for (; int x = v; ) // { dg-message "'int x' previously declared here" } + int x; // { dg-error "redeclaration of 'int x'" } + try + { + } + catch (int x) // { dg-message "'int x' previously declared here" } + { + int x; // { dg-error "redeclaration of 'int x'" } + } + if (int x = 1) + if (int x = 1) + ; + if (int x = 0) + ; + else + if (int x = 1) + ; + if (int x = 1) + switch (int x = 1) + ; + if (int x = 0) + while (int x = v) + ; + if (int x = 0) + for (int x = v; x; ++x) + ; + switch (int x = 1) + switch (int x = 1) + { + case 1:; + } + while (int x = 0) + if (int x = 1) + ; + for (int x = v; x; ++x) + for (int x = v; x; ++x) + ; +} + +void +qux (int x) // { dg-message "'int x' previously declared here" } +try +{ +} +catch (int x) // { dg-error "redeclaration of 'int x'" } +{ +} + +void +corge (int x) // { dg-message "'int x' previously declared here" } +try +{ +} +catch (...) +{ + int x; // { dg-error "redeclaration of 'int x'" } +} + +void +fred (int x) // { dg-message "'int x' previously declared here" } +try +{ +} +catch (int) +{ +} +catch (long) +{ + int x; // { dg-error "redeclaration of 'int x'" } +} + +void +garply (int x) +{ + try + { + int x; + } + catch (...) + { + int x; + } +} + +struct S +{ + S (int x) // { dg-message "'int x' previously declared here" } + try : s (x) + { + int x; // { dg-error "declaration of 'int x' shadows a parameter" } + } + catch (...) + { + } + int s; +}; + +struct T +{ + T (int x) // { dg-message "'int x' previously declared here" } + try : t (x) + { + } + catch (...) + { + int x; // { dg-error "redeclaration of 'int x'" } + } + int t; +}; + +struct U +{ + U (int x) : u (x) + { + try + { + int x; + } + catch (...) + { + int x; + } + } + int u; +}; + +struct V +{ + V (int x) : v (x) + { + { + int x; + } + } + int v; +}; + +void +foobar (int x) +try +{ +} +catch (int) +{ + try + { + } + catch (int x) + { + } + try + { + } catch (int) + { + int x; + } +}