From patchwork Sat Dec 24 19:03:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Charlie Sale X-Patchwork-Id: 36440 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:4e01:0:0:0:0:0 with SMTP id p1csp265818wrt; Sat, 24 Dec 2022 11:04:49 -0800 (PST) X-Google-Smtp-Source: AMrXdXvVGbF9h4BTR535DX9p2NIrK/ykgFpp9JuLa3SCoYZLHFKER4Lapy1o6ztxx9KmTJrwwtBw X-Received: by 2002:a05:6402:88d:b0:46d:1c38:1537 with SMTP id e13-20020a056402088d00b0046d1c381537mr11441166edy.29.1671908689684; Sat, 24 Dec 2022 11:04:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1671908689; cv=none; d=google.com; s=arc-20160816; b=JzfGGnu4nknY1hjBk+ZCBRjhINaCVTIpKnhG+cJABPikRMvQrRezEPs7giCLjBYjDL S4+ay9A0npOwq3tuexU50vc0lCWLgER5X5fn2YP+usF6oslwA1cobqvT9qAu3GjqXGLf yLk0hhOm9yqj8YykhI/wtjvag1QT1s9XIuPc3yS+uMxIuiyKoEa8IEBdgwCc4NVHhFjS FUuyR5zJ4zyzTY6sPsMF8ixcXf84tPRS1XyB2SCBiPH4SBJECLUBr3W2lC2RHS1tlVdc OLZnF4i+e9e1pX0zC0aThphPhpwUSOtVUUROZrllsMMup7+3T4la0AVrxh8r+J16HJ7h PxsQ== 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=DM5Pays6z/7FPkeAw43quiSCB7ZkYHdwQh1EB6UhrAoH6+RxM3ZWbfmnkVgoUVI3NB Wny00EDYXNOOwFAc9ZoZY6iQ1upkxjOlUk1Dn5kIEudMTHWGjxWapK4FZRe1MP/lEkMe fUjBP9S/caDO9Xe8XcM8INZGUCw1pMNqX8dycE0sQi8qxWx0KcfUO6YAfbEPw57BzAPF uonS5jrGHajzuOz57L8mit/BfX8lF4KEF9xFEw1fWh4ENjKUzW6CpoYZ3h2z/MGwQkcL niamsZ7oyoQw5xawz/qjnpdKZuAwQ3LpSO3FFUmphPcMH4Uh0CTne7COukfqa9BQJ9F3 1NDw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=uMkr5rZJ; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 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. [8.43.85.97]) by mx.google.com with ESMTPS id o7-20020a056402038700b00482ab84faf4si2501589edv.572.2022.12.24.11.04.49 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Dec 2022 11:04:49 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=uMkr5rZJ; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 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 D02D63850F0B for ; Sat, 24 Dec 2022 19:04:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D02D63850F0B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1671908687; 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=uMkr5rZJJpPc7QgtTM/ZjdnMyeJiBU81tTl7Fyj1kvhO0OxhC5Or5k7WaAMkFnkUc X9Na1pu2raNZzHMmHNrUkj6Blz5SYdpa5uT0p5gkW65+ukJTfVpAxOcIUfo+Pqe3Tk I5iFVm71567W2+sGxc1TgiHDSNe72PH9xQ+tJUG0= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qt1-x835.google.com (mail-qt1-x835.google.com [IPv6:2607:f8b0:4864:20::835]) by sourceware.org (Postfix) with ESMTPS id BCA033858D1E for ; Sat, 24 Dec 2022 19:04:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BCA033858D1E Received: by mail-qt1-x835.google.com with SMTP id c11so6017566qtn.11 for ; Sat, 24 Dec 2022 11:04:01 -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=0SUAUuFp2pFMHOCZut1Nrvb/j6cBowBDZ1k5rJToXgF4s55qrb+1auHL2BR3S+ft8O wYIv1liC7mq3CWpniQBk4lDdkmUzArr392wlZM0xegUmIwspJWM3si9ikrxDpoosBmtJ fShSwF4XreeVDdOyU9jjnjnP+QQFqp9jhgnoJN5M3EcHdZRqaklHOT+S7vzaRAc4Gsiw JMhWPvR7FdWB30q+eYfQjP2yly4cMMvHlH+lRXuGUXxnCB9ZO+HlaXMIfDa7pCREt4xI LPREGJiWvJDNvBOVv1t+ucwfixp1ngEDOjelMS/vr5pnYY0o4US6CGsLRtPLbn5ZFzLB Scfw== X-Gm-Message-State: AFqh2kpB86yPzOtvyJfHPK4ufgS/qRXHnO5T1gUc2z5hQYAmQmyjpVNJ iRQPjCpE7cD5CeQYfbJtX+CgbhP44R4= X-Received: by 2002:ac8:5295:0:b0:3a8:fdf:8ff8 with SMTP id s21-20020ac85295000000b003a80fdf8ff8mr16692690qtn.36.1671908640741; Sat, 24 Dec 2022 11:04:00 -0800 (PST) Received: from triangulum.attlocal.net ([2600:1700:8c20:f0b0::42]) by smtp.gmail.com with ESMTPSA id d18-20020ac847d2000000b0039cc82a319asm3815311qtr.76.2022.12.24.11.03.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 24 Dec 2022 11:04:00 -0800 (PST) To: gcc-patches@gcc.gnu.org Cc: Charlie Sale Subject: [PATCH] cp: warn uninitialized const/ref in base class [PR80681] Date: Sat, 24 Dec 2022 14:03:43 -0500 Message-Id: <20221224190343.3490-1-softwaresale01@gmail.com> X-Mailer: git-send-email 2.38.1 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?1753123326402802030?= X-GMAIL-MSGID: =?utf-8?q?1753123326402802030?= 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 +{ +}; +