From patchwork Wed Jan 4 17:54:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Charlie Sale X-Patchwork-Id: 39045 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:4e01:0:0:0:0:0 with SMTP id p1csp5274011wrt; Wed, 4 Jan 2023 09:55:34 -0800 (PST) X-Google-Smtp-Source: AMrXdXuK/PIrQ1fTXam7gV/G4kj9yYImF4fUsTTIDKsPzJZ8DrlCIZh72OPeqbTLpnGWl69CLN5x X-Received: by 2002:a17:906:6a0a:b0:7c9:6e0e:1427 with SMTP id qw10-20020a1709066a0a00b007c96e0e1427mr46943215ejc.6.1672854934361; Wed, 04 Jan 2023 09:55:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1672854934; cv=none; d=google.com; s=arc-20160816; b=WnQmnsGLLFPOSGyHnQgXsgqpB7OQifYbMYc/PnTZ5n6sCml32agyZ/eVp4NhzCU9+M dLLLpbglGlPYsS6b822MzhiITnDUahbM56VjzZjAVd7OEKTiTm79Ffqdm2Q/WGAN2wBP UoyBYTTwGmvDE3gbbuP/9kflLL8L4++Z7wSf0dUsNFfXlynK22cgyfc2XuCDGKZpO0zO NDuwC5GJ62Mn67qI5KFYf2cr0IxUDUGkmpGblYPzkUB2+eNxQn3FvfrRkcGj6hcYoAoP ZYVnCxjDBfe9YKzO1y1+hKUyhMwxTArVFzL7Y69qyNCKiWhnFNRnr3dIFlXLSR3nPQHF GiSQ== 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-transfer-encoding:mime-version:message-id:date:subject:cc :to:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=AqRvqB8QyI+MTFQ5zEs7bxlfvim7GUTiLZaf9CCajs0=; b=gwsuDewnHiW8KpDOczBbFpSLhWISWYtiVaBFCpDrzjcK+1gOYSpIF0CH8QAotdvSXH lJ78oJsJrgXJoyEF9NNzb6VVGoNIYzqV/OwwuKBg8jx2cZzXw3ED0X6qm437ddnUNxHv tISiBq93wkRPHX5lNPo1zz1ML8/YlQVpyoPBWtIAWFAjKlQoZt3ztSRX9RcMAt/DKcTe bq0D369FL0V4tL8vZ7FI0ND9UnnxKa601phldPjWzE/ZeawNZQZRvky7XSrJQ1kpfmee ZrCcL0myhtAefEzJPGsB+qxCW5wbZD5ug6FZsLzpV+EqLjbgx1wKRLtd0hdaHiJM8NvP 8W2g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=nVdaQAk5; 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 sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id l10-20020a170906794a00b007806a130086si32702013ejo.302.2023.01.04.09.55.34 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Jan 2023 09:55:34 -0800 (PST) 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=nVdaQAk5; 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 2CFF23858C30 for ; Wed, 4 Jan 2023 17:55:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2CFF23858C30 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1672854933; bh=AqRvqB8QyI+MTFQ5zEs7bxlfvim7GUTiLZaf9CCajs0=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=nVdaQAk5V/IPG7uy5fKP8fJpkQinaKcRfRRwtQRM9ho98W2hB96LMYXvT8r4P2iQq K5JV3iurb7kYEJVpyc217HVCV7yh1z1sAtTfSVkpf+MivqR3rfnGfdqRjz2NMgJrrj 3a+ydmNBGlQMDl52FIRNJ9SpRrcp13nRTHVfDZ8Q= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qv1-xf36.google.com (mail-qv1-xf36.google.com [IPv6:2607:f8b0:4864:20::f36]) by sourceware.org (Postfix) with ESMTPS id 8927E3858D35 for ; Wed, 4 Jan 2023 17:54:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8927E3858D35 Received: by mail-qv1-xf36.google.com with SMTP id d13so23941156qvj.8 for ; Wed, 04 Jan 2023 09:54:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=AqRvqB8QyI+MTFQ5zEs7bxlfvim7GUTiLZaf9CCajs0=; b=lqpJt8BIuMzhuS/Ayvvl3cZi0sb2B+0ehAoJsWs38dZcv6b8i0kyLuXw6vNCe7qENy uT8ulJEpMVdihIZY2PbeEwO5PFZet6ujL9mXr+bfmvuOfQvTaxKAlq87xobskbDsjDg6 Qlssvn3fNJ2BbN9MQci9r+qhJAo6aBTlwsPt8pMoA66dNxDsra9qjnXPwcChWq81Woxu isTtRrLANxnHKUaf38QD6XFd77rzhl3ogpQAjIJuCFJb+LNsueD55QXzAze6kP999F2j ujHjIdaHaV3CL8KxxdK7dN5kpUqeLk9T0YpvP3bGlR92PSEcS1DFiIV9fyWkly22jCd8 9cKA== X-Gm-Message-State: AFqh2kphSj2grCG/bIEZwL2+fo/DFugSIxU0cNpcpwTlFYGUIHgJmQHv z9PIM5/7s7sKSqD6lD3QdnpPFnWfUNw= X-Received: by 2002:a05:6214:18f0:b0:531:80b2:1f64 with SMTP id ep16-20020a05621418f000b0053180b21f64mr46069982qvb.51.1672854887431; Wed, 04 Jan 2023 09:54:47 -0800 (PST) Received: from triangulum.attlocal.net ([2600:1700:8c20:f0b0::22]) by smtp.gmail.com with ESMTPSA id q10-20020a05620a0d8a00b006b949afa980sm24165293qkl.56.2023.01.04.09.54.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Jan 2023 09:54:46 -0800 (PST) To: gcc-patches@gcc.gnu.org Cc: Charlie Sale Subject: [ping][PATCH] cp: warn uninitialized const/ref in base class [PR80681] Date: Wed, 4 Jan 2023 12:54:09 -0500 Message-Id: <20230104175408.4437-1-softwaresale01@gmail.com> X-Mailer: git-send-email 2.39.0 MIME-Version: 1.0 X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Charlie Sale via Gcc-patches From: Charlie Sale Reply-To: Charlie Sale Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1754115535354039048?= X-GMAIL-MSGID: =?utf-8?q?1754115535354039048?= On this example: ``` struct Fine { private: const int f; }; struct BuggyA { const int a; int &b; }; struct BuggyB : private BuggyA { }; ``` g++ currently emits: ``` test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class without a constructor [-Wuninitialized] 3 | const int f; | ``` (relevant godbolt: https://godbolt.org/z/KGMK6e1zc) The issue here is that g++ misses the uninitialized const and ref members in BuggyA that are inherited as private in BuggyB. It should warn about those members when checking BuggyB. With this patch, g++ emits the following: ``` test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class without a constructor [-Wuninitialized] 3 | const int f; | ^ test.cc:7:19: warning: while processing ‘BuggyB’: non-static const member ‘const int BuggyA::a’ in class without a constructor [-Wuninitialized] 7 | const int a; | ^ test.cc:7:19: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields contained within ‘BuggyA’ are private to ‘BuggyB’ test.cc:8:14: warning: while processing ‘BuggyB’: non-static reference ‘int& BuggyA::b’ in class without a constructor [-Wuninitialized] 8 | int &b; | ^ test.cc:8:14: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields contained within ‘BuggyA’ are private to ‘BuggyB’ ``` Now, the compiler warns about the uninitialized members. In terms of testing, I added three tests: - a status quo test that makes sure that the existing warning behavior works - A simple test based off of the PR - Another example with multiple inheritance - A final example with mutliple levels of inheritance. These tests all pass. I also bootstrapped the project without any regressions. PR c++/80681 gcc/cp/ChangeLog: * class.cc (warn_uninitialized_const_and_ref): Extract warn logic into new func, add inform for inheritance warning (check_bases_and_members): Move warn logic to warn_unintialized_const_and_ref, check subclasses for warnings as well gcc/testsuite/ChangeLog: * g++.dg/pr80681-1.C: New test. Signed-off-by: Charlie Sale --- gcc/cp/class.cc | 110 +++++++++++++++++++++++++------ gcc/testsuite/g++.dg/pr80681-1.C | 51 ++++++++++++++ 2 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/g++.dg/pr80681-1.C diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index aebcb53739e..72172bea6ad 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -6018,6 +6018,76 @@ explain_non_literal_class (tree t) } } + +/* Warn for private const or reference class members that cannot be initialized + due to the class not having a default constructor. If a child type is + provided, then we are checking class_type's members in case they cannot be + initialized by child_type. If child_type is null, then we simply check + class_type. */ +static void +warn_uninitialized_const_and_ref (tree class_type, tree child_type) +{ + /* Check the fields on this class type. */ + tree field; + for (field = TYPE_FIELDS (class_type); field; field = DECL_CHAIN (field)) + { + /* We only want to check variable declarations. + Exclude fields that are not field decls or are not initialized. */ + if (TREE_CODE (field) != FIELD_DECL + || DECL_INITIAL (field) != NULL_TREE) + continue; + + tree type = TREE_TYPE (field); + + if (TYPE_REF_P (type)) + { + if (child_type != nullptr) + { + /* Show parent class while processing. */ + auto_diagnostic_group d; + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wuninitialized, "while processing %qE: " + "non-static reference %q#D in class without a constructor", + child_type, field); + inform (DECL_SOURCE_LOCATION (field), + "%qE inherits %qE as private, so all fields " + "contained within %qE are private to %qE", + child_type, class_type, class_type, child_type); + } + else + { + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wuninitialized, "non-static reference %q#D " + "in class without a constructor", field); + } + } + else if (CP_TYPE_CONST_P (type) + && (!CLASS_TYPE_P (type) + || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) + { + if (child_type) + { + /* ditto. */ + auto_diagnostic_group d; + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wuninitialized, "while processing %qE: " + "non-static const member %q#D in class " + "without a constructor", child_type, field); + inform (DECL_SOURCE_LOCATION (field), + "%qE inherits %qE as private, so all fields " + "contained within %qE are private to %qE", + child_type, class_type, class_type, child_type); + } + else + { + warning_at (DECL_SOURCE_LOCATION (field), + OPT_Wuninitialized, "non-static const member %q#D " + "in class without a constructor", field); + } + } + } +} + /* Check the validity of the bases and members declared in T. Add any implicitly-generated functions (like copy-constructors and assignment operators). Compute various flag bits (like @@ -6160,30 +6230,32 @@ check_bases_and_members (tree t) initializers. */ && CLASSTYPE_NON_AGGREGATE (t)) { - tree field; + /* First, warn for this class. */ + warn_uninitialized_const_and_ref (t, nullptr /* no child class. */); - for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) - { - tree type; + /* Then, warn for any direct base classes. This process will not + descend all base classes, just the ones directly inherited by + this class. */ + tree binfo, base_binfo; + int idx; - if (TREE_CODE (field) != FIELD_DECL - || DECL_INITIAL (field) != NULL_TREE) - continue; + for (binfo = TYPE_BINFO (t), idx = 0; + BINFO_BASE_ITERATE (binfo, idx, base_binfo); idx++) + { + tree basetype = TREE_TYPE (base_binfo); - type = TREE_TYPE (field); - if (TYPE_REF_P (type)) - warning_at (DECL_SOURCE_LOCATION (field), - OPT_Wuninitialized, "non-static reference %q#D " - "in class without a constructor", field); - else if (CP_TYPE_CONST_P (type) - && (!CLASS_TYPE_P (type) - || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type))) - warning_at (DECL_SOURCE_LOCATION (field), - OPT_Wuninitialized, "non-static const member %q#D " - "in class without a constructor", field); + /* Base types are not going to be aggregates, so don't + check for that. Otherwise, this step will never happen. */ + if (!TYPE_HAS_USER_CONSTRUCTOR (basetype) + || CLASSTYPE_NON_AGGREGATE (basetype)) + { + /* Repeat the same process on base classes, know that 't' + is a child_class of basetype. */ + warn_uninitialized_const_and_ref (basetype, t); + } } - } + } /* Synthesize any needed methods. */ add_implicitly_declared_members (t, &access_decls, cant_have_const_ctor, diff --git a/gcc/testsuite/g++.dg/pr80681-1.C b/gcc/testsuite/g++.dg/pr80681-1.C new file mode 100644 index 00000000000..40eab653aca --- /dev/null +++ b/gcc/testsuite/g++.dg/pr80681-1.C @@ -0,0 +1,51 @@ +// PR c++/80681 +// { dg-do compile } +// { dg-options "-Wuninitialized -c" } + +/* Status quo: the original should still warn correctly. */ +struct StatusQuo +{ +private: + const int a; // { dg-warning "non-static const member" } + int &b; // { dg-warning "non-static reference" } +}; + +/* Single layer of inheritance. */ +struct A { + const int a; // { dg-warning "non-static const member" } + int &b; // { dg-warning "non-static reference" } +}; + +struct B: private A { +}; + +/* multiple inheritance example. */ +struct X +{ + const int x; // { dg-warning "non-static const member" } +}; + +struct Y +{ + const int &y; // { dg-warning "non-static reference" } +}; + +struct Z : private Y, private X +{ +}; + +/* multi-level inheritance example. */ +struct M +{ + const int x; // { dg-warning "non-static const member" } +}; + +struct N: private M +{ + const int &y; // { dg-warning "non-static reference" } +}; + +struct O: private N +{ +}; +