From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by sourceware.org (Postfix) with ESMTPS id E4C773854812 for ; Tue, 5 Jan 2021 14:25:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E4C773854812 Received: by mail-ej1-x62e.google.com with SMTP id n26so41415720eju.6 for ; Tue, 05 Jan 2021 06:25:14 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=evxkTRfZxINKCrQa+Kt8eUFxaYwA/8YPTZLuwf0nsjU=; b=QVEZ0jtNnc3y0nU19WaW8QLSe/a2wCG5DBN7DSUT3QqIgHnSCHG4ma4vA1ev5Wc241 b1yl+okVZHwG3V3ywtzprjVZpv1PkFE0+QX7uS8GO0qN1be1LxE72IT0V3MDrtdStfsw +pjh+0mq1u5sDsdmgEm/MLojE466SGeAh4COozJ59VbvRC9fCB2wXKrVyoZ+hIFQAJR1 1+zSHryr7/6FyPI6ROjDexzKW4u/CXrU2QDEDKFJFmLx/DzDQQVZQfPyd+ZItvr5cabB coexNV3Gm/XZXlWY6AMj3YRZivfnadrgy4qb0g+CY2MsPR5WE77xVQVxX3US+HY/4YFf wbeA== X-Gm-Message-State: AOAM53077X8yQ5O3TyjcFOBfKcMGidNlxj4BAWmM5N0PdcAoEZ29ru9o 1V8EdqE6QE4+HSh0aFwwl2zx0I0dOj6SCnvUGlXKblzsLHkQIA== X-Google-Smtp-Source: ABdhPJxurgVyyqblhy+Q9Q4Rmts9EvW9HLLXWiZDUtpwUUkbQnjUNV8ZWNGLRIbLsESqEi1W976A5bGWThPExFN9b3w= X-Received: by 2002:a17:906:3781:: with SMTP id n1mr40907222ejc.296.1609856713245; Tue, 05 Jan 2021 06:25:13 -0800 (PST) MIME-Version: 1.0 From: Anthony Sharp Date: Tue, 5 Jan 2021 14:24:36 +0000 Message-ID: Subject: [PATCH] c++: private inheritance access diagnostics fix [PR17314] To: gcc-patches@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-1.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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-List-Received-Date: Tue, 05 Jan 2021 14:25:17 -0000 This patch fixes PR17314 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17314). Previously, when class C attempted to access member a declared in class A through class B, where class B privately inherits from A and class C inherits from B, GCC would correctly report an access violation, but would erroneously report that the reason was because a was "protected", when in fact, from the point of view of class C, it was "private". This patch updates the diagnostics code to generate more correct errors in cases of failed inheritance such as these. The reason this bug happened was because GCC was examining the declared access of decl, instead of looking at it in the context of class inheritance. ----------- COMMENTS ----------- This is my first GCC patch ever so there is probably something I have done very wrong. Please let me know :) The thought of my code being scrutinised by people with PhDs and doctorates is quite frankly terrifying. Note that since it is a new year I had to make a new changelog file so the diff for the patch might be slightly off. There was no need to add additional regression tests since it was adequate to simply change some of the regression tests that were there originally (all the patch changes is the informative message telling the user where a decl was defined as private). ----------- REGRESSION ANALYSIS ----------- No regressions reported. G++ (CLEAN) RESULTS # of expected passes 202879 # of unexpected failures 1 # of expected failures 988 # of unsupported tests 8654 GCC (CLEAN) RESULTS # of expected passes 163377 # of unexpected failures 94 # of unexpected successes 37 # of expected failures 915 # of unsupported tests 2530 G++ (PR17314 PATCHED) RESULTS # of expected passes 202871 # of unexpected failures 1 # of expected failures 988 # of unsupported tests 8654 GCC (PR17314 PATCHED) RESULTS # of expected passes 163377 # of unexpected failures 94 # of unexpected successes 37 # of expected failures 915 # of unsupported tests 2530 When I build and make -k check -j 6 on the patched source it reports 202871 passes (8 fewer), although the FAILs do not increase. I am not 100% sure why this happens since I have not removed any testcases, only edited a few, but I think this happens because in files like dr142.c I removed more output checks than I added. make -k check -j 6 also returns error 2 sometimes, although there are no obvious errors or warnings in the logs explaining why. Probably harmless? ----------- BUILD REPORT ----------- GCC builds normally on x86_64-pc-linux-gnu for x86_64-pc-linux-gnu using make -j 6. I didn't see it necessary to test on other build targets since the patch only affects the C++ front end and so functionality is unlikely to differ between platforms. The compile log reports: Comparing stages 2 and 3 warning: gcc/cc1obj-checksum.o differs Comparison successful. and then continues. I assume this means it was actually successful. Index: gcc/cp/ChangeLog from Anthony Sharp Fixes PR17314 * typeck.c (complain_about_unrecognized_member): Updated function arguments in complain_about_access. * call.c (complain_about_access): Altered function. * semantics.c (get_parent_with_private_access): Added function. (access_in_type): Added as extern function. * search.c (access_in_type): Made function non-static so it can be used in semantics.c. * cp-tree.h (complain_about_access): Changed parameters of function. Index: gcc/testsuite/ChangeLog from Anthony Sharp Fixes PR17314 * g++.dg/lookup/scoped1.c modified testcase to run successfully with changes. * g++.dg/tc1/dr142.c modified testcase to run successfully with changes. * g++.dg/tc1/dr142.c modified testcase to run successfully with changes. * g++.dg/tc1/dr142.c modified testcase to run successfully with changes. * g++.dg/tc1/dr52.c modified testcase to run successfully with changes. * g++.old-deja/g++.brendan/visibility6.c modified testcase to run successfully with changes. * g++.old-deja/g++.brendan/visibility8.c modified testcase to run successfully with changes. * g++.old-deja/g++.jason/access8.c modified testcase to run successfully with changes. * g++.old-deja/g++.law/access4.c modified testcase to run successfully with changes. * g++.old-deja/g++.law/visibility12.c modified testcase to run successfully with changes. * g++.old-deja/g++.law/visibility4.c modified testcase to run successfully with changes. * g++.old-deja/g++.law/visibility8.c modified testcase to run successfully with changes. * g++.old-deja/g++.other/access4.c modified testcase to run successfully with changes. Index: gcc/testsuite/g++.old-deja/g++.jason/access8.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.jason/access8.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.jason/access8.C 2021-01-03 00:22:14.969854000 +0000 @@ -4,5 +4,5 @@ // Bug: g++ forgets access decls after the definition. -class inh { // { dg-message "" } inaccessible +class inh { int a; protected: @@ -10,5 +10,6 @@ protected: }; -class mel : private inh { +class mel : private inh // { dg-message "" } inaccessible +{ protected: int t; Index: gcc/testsuite/g++.old-deja/g++.law/access4.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.law/access4.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.law/access4.C 2021-01-03 00:21:01.736320000 +0000 @@ -7,10 +7,11 @@ // Message-ID: <9403030024.AA04534@ses.com> -class ForceLeafSterile { // { dg-message "" } +class ForceLeafSterile { friend class Sterile; ForceLeafSterile() {} // { dg-message "" } }; -class Sterile : private virtual ForceLeafSterile { +class Sterile : private virtual ForceLeafSterile // { dg-message "" } +{ public: Sterile() {} Index: gcc/testsuite/g++.old-deja/g++.law/visibility12.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.law/visibility12.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.law/visibility12.C 2021-01-03 00:20:24.243535000 +0000 @@ -7,9 +7,10 @@ // Message-ID: <9306300528.AA17185@coda.mel.dit.CSIRO.AU> struct a { - int aa; // { dg-message "" } private + int aa; }; -class b : private a { - }; +class b : private a // { dg-message "" } private +{ +}; class c : public b { Index: gcc/testsuite/g++.old-deja/g++.law/visibility8.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.law/visibility8.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.law/visibility8.C 2021-01-03 00:19:45.574725000 +0000 @@ -8,9 +8,10 @@ class t1 { protected: - int a; // { dg-message "" } protected + int a; }; -class t2 : private t1 { +class t2 : private t1 // { dg-message "" } protected +{ public: int b; Index: gcc/testsuite/g++.old-deja/g++.law/visibility4.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.law/visibility4.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.law/visibility4.C 2021-01-03 00:20:06.815170000 +0000 @@ -9,8 +9,9 @@ class A { public: - int b; // { dg-message "" } private + int b; }; -class C : private A { // NOTE WELL. private, not public +class C : private A // { dg-message "" } private +{ public: int d; Index: gcc/testsuite/g++.old-deja/g++.other/access4.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.other/access4.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.other/access4.C 2021-01-03 00:19:25.362302000 +0000 @@ -1,9 +1,9 @@ // { dg-do assemble } -struct A { // { dg-message "" } inaccessible +struct A { static int i; }; -struct B : private A { }; +struct B : private A { }; // { dg-message "" } inaccessible struct C : public B { Index: gcc/testsuite/g++.old-deja/g++.brendan/visibility8.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.brendan/visibility8.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.brendan/visibility8.C 2021-01-03 00:19:17.918146000 +0000 @@ -6,7 +6,7 @@ class foo { public: - static int y; // { dg-message "" } private + static int y; }; -class foo1 : private foo +class foo1 : private foo // { dg-message "" } private { }; class foo2 : public foo1 Index: gcc/testsuite/g++.old-deja/g++.brendan/visibility6.C =================================================================== --- gcc/testsuite/g++.old-deja/g++.brendan/visibility6.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.old-deja/g++.brendan/visibility6.C 2021-01-03 00:21:55.873454000 +0000 @@ -4,7 +4,7 @@ class bottom { public: - int b; // { dg-message "" } private + int b; }; -class middle : private bottom +class middle : private bottom // { dg-message "" } private { public: Index: gcc/testsuite/g++.dg/lookup/scoped1.C =================================================================== --- gcc/testsuite/g++.dg/lookup/scoped1.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.dg/lookup/scoped1.C 2021-01-02 21:51:30.088674000 +0000 @@ -5,10 +5,10 @@ struct A { static int i1; - int i2; // { dg-message "declared" } + int i2; static void f1 (); void f2 (); }; -struct B: private A { }; +struct B: private A { }; // { dg-message "declared" } struct C: public B { Index: gcc/testsuite/g++.dg/tc1/dr142.C =================================================================== --- gcc/testsuite/g++.dg/tc1/dr142.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.dg/tc1/dr142.C 2021-01-02 21:54:09.839546000 +0000 @@ -3,11 +3,11 @@ // DR142: Injection-related errors in access example -class B { // { dg-message "declared" } +class B { public: - int mi; // { dg-message "declared" } - static int si; // { dg-message "declared" } + int mi; + static int si; }; -class D: private B { +class D: private B { // { dg-message "declared" } }; Index: gcc/testsuite/g++.dg/tc1/dr52.C =================================================================== --- gcc/testsuite/g++.dg/tc1/dr52.C 2020-12-31 16:51:34.000000000 +0000 +++ gcc/testsuite/g++.dg/tc1/dr52.C 2021-01-03 13:20:08.267946000 +0000 @@ -18,9 +18,9 @@ struct B2 : B {}; struct C -{ // { dg-message "declared" } - void foo(void); +{ + void foo(void); }; -struct D : private C {}; +struct D : private C {}; // { dg-message "declared" } struct X: A, B1, B2, D Index: gcc/cp/semantics.c =================================================================== --- gcc/cp/semantics.c 2020-12-31 16:51:34.000000000 +0000 +++ gcc/cp/semantics.c 2021-01-04 20:26:51.912302840 +0000 @@ -47,4 +47,6 @@ along with GCC; see the file COPYING3. #include "memmodel.h" +extern access_kind access_in_type (tree type, tree decl); + /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -257,4 +259,39 @@ pop_to_parent_deferring_access_checks (v } +/* This deals with bug PR17314. + + DECL is a declaration and BINFO represents a class that has attempted (but + failed) to access DECL. + + Examine the parent binfos of BINFO and determine whether any of them had + private access to DECL. If they did, return the parent binfo. This helps + in figuring out the correct error message to show (if the parents had + access, it's their fault for not giving sufficient access to BINFO). + + If no parents had access, return NULL_TREE. */ + +static tree +get_parent_with_private_access(tree decl, tree binfo) +{ + /* Only BINFOs should come through here. */ + gcc_assert(TREE_CODE(binfo) == TREE_BINFO); + + tree base_binfo = NULL_TREE; + + /* Iterate through immediate parent classes. */ + for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + /* This parent had private access. Therefore that's why BINFO can't access + DECL. */ + if(access_in_type(BINFO_TYPE(base_binfo), decl) == ak_private) + return base_binfo; + } + + /* None of the parents had access. Note: it's impossible for one of the + parents to have had public or protected access to DECL, since then + BINFO would have been able to access DECL too. */ + return NULL_TREE; +} + /* If the current scope isn't allowed to access DECL along BASETYPE_PATH, give an error, or if we're parsing a function or class @@ -315,9 +352,34 @@ enforce_access (tree basetype_path, tree { if (flag_new_inheriting_ctors) - diag_decl = strip_inheriting_ctors (diag_decl); + diag_decl = strip_inheriting_ctors (diag_decl); if (complain & tf_error) - complain_about_access (decl, diag_decl, true); + { + /* We will usually want to point to the same place as diag_decl but + not always. */ + tree diag_location = diag_decl; + access_kind parent_access = ak_none; + + /* See if any of BASETYPE_PATH's parents had private access to DECL. + If they did, that will tell us why we don't. */ + tree parent_binfo = get_parent_with_private_access(decl, basetype_path); + + /* If a parent had private access, then the diagnostic location DECL + should be that of the parent class, since it failed to give suitable + access by using a private inheritance. But if DECL was actually defined + in the parent, it wasn't privately inherited, and so we don't need to + do this, and complain_about_access will figure out what to do. */ + if(parent_binfo != NULL_TREE + && context_for_name_lookup(decl) != BINFO_TYPE(parent_binfo)) + { + diag_location = TYPE_NAME(BINFO_TYPE(parent_binfo)); + parent_access = ak_private; + } + + /* Finally, generate an error message. */ + complain_about_access (decl, diag_decl, diag_location, true, + parent_access); + } if (afi) - afi->record_access_failure (basetype_path, decl, diag_decl); + afi->record_access_failure (basetype_path, decl, diag_decl); return false; } Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h 2020-12-31 16:51:34.000000000 +0000 +++ gcc/cp/cp-tree.h 2021-01-01 01:33:03.194982000 +0000 @@ -6435,5 +6435,5 @@ class access_failure_info }; -extern void complain_about_access (tree, tree, bool); +extern void complain_about_access (tree, tree, tree, bool, access_kind); extern void push_defarg_context (tree); extern void pop_defarg_context (void); Index: gcc/cp/search.c =================================================================== --- gcc/cp/search.c 2020-12-31 16:51:34.000000000 +0000 +++ gcc/cp/search.c 2021-01-01 01:33:56.788180000 +0000 @@ -48,5 +48,5 @@ static tree dfs_walk_once_accessible (tr void *data); static tree dfs_access_in_type (tree, void *); -static access_kind access_in_type (tree, tree); +access_kind access_in_type (tree, tree); static tree dfs_get_pure_virtuals (tree, void *); @@ -584,5 +584,5 @@ dfs_access_in_type (tree binfo, void *da /* Return the access to DECL in TYPE. */ -static access_kind +access_kind access_in_type (tree type, tree decl) { Index: gcc/cp/typeck.c =================================================================== --- gcc/cp/typeck.c 2020-12-31 16:51:34.000000000 +0000 +++ gcc/cp/typeck.c 2021-01-01 01:37:13.602815000 +0000 @@ -2981,5 +2981,6 @@ complain_about_unrecognized_member (tree ? TREE_TYPE (access_path) : object_type, name, afi.get_diag_decl ()); - complain_about_access (afi.get_decl (), afi.get_diag_decl (), false); + complain_about_access (afi.get_decl (), afi.get_diag_decl (), + afi.get_diag_decl (), false, ak_none); } } Index: gcc/cp/call.c =================================================================== --- gcc/cp/call.c 2020-12-31 16:51:34.000000000 +0000 +++ gcc/cp/call.c 2021-01-04 19:40:18.564108581 +0000 @@ -7133,31 +7133,49 @@ build_op_delete_call (enum tree_code cod in the diagnostics. - If ISSUE_ERROR is true, then issue an error about the - access, followed by a note showing the declaration. - Otherwise, just show the note. */ + If ISSUE_ERROR is true, then issue an error about the access, followed + by a note showing the declaration. Otherwise, just show the note. + + DIAG_DECL and DIAG_LOCATION will almost always be the same. + DIAG_LOCATION is just another DECL. NO_ACCESS_REASON is an optional + parameter used to specify why DECL wasn't accessible (e.g. ak_private + would be because DECL was private). If not using NO_ACCESS_REASON, + then it must be ak_none, and the access failure reason will be + figured out by looking at the protection of DECL. */ void -complain_about_access (tree decl, tree diag_decl, bool issue_error) +complain_about_access (tree decl, tree diag_decl, tree diag_location, +bool issue_error, access_kind no_access_reason) { - if (TREE_PRIVATE (decl)) - { - if (issue_error) - error ("%q#D is private within this context", diag_decl); - inform (DECL_SOURCE_LOCATION (diag_decl), - "declared private here"); - } - else if (TREE_PROTECTED (decl)) - { - if (issue_error) - error ("%q#D is protected within this context", diag_decl); - inform (DECL_SOURCE_LOCATION (diag_decl), - "declared protected here"); - } + /* If we have not already figured out why DECL is innaccessible... */ + if (no_access_reason == ak_none) + { + /* Examine the access of DECL to find out why. */ + if (TREE_PRIVATE (decl)) + no_access_reason = ak_private; + else if (TREE_PROTECTED (decl)) + no_access_reason = ak_protected; + } + + /* Now generate an error message depending on calculated access. */ + if (no_access_reason == ak_private) + { + if (issue_error) + error ("%q#D is private within this context", diag_decl); + inform (DECL_SOURCE_LOCATION (diag_location), "declared private here"); + } + else if (no_access_reason == ak_protected) + { + if (issue_error) + error ("%q#D is protected within this context", diag_decl); + inform (DECL_SOURCE_LOCATION (diag_location), "declared protected here"); + } + /* Couldn't figure out why DECL is innaccesible, so just say it's + innaccessible. */ else - { - if (issue_error) - error ("%q#D is inaccessible within this context", diag_decl); - inform (DECL_SOURCE_LOCATION (diag_decl), "declared here"); - } + { + if (issue_error) + error ("%q#D is inaccessible within this context", diag_decl); + inform (DECL_SOURCE_LOCATION (diag_decl), "declared here"); + } }