From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2122) id 6F42D3858404; Mon, 30 Aug 2021 21:27:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6F42D3858404 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jason Merrill To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-3236] c++: limit instantiation with ill-formed class [PR96286] X-Act-Checkin: gcc X-Git-Author: Jason Merrill X-Git-Refname: refs/heads/master X-Git-Oldrev: 729f6881cfcc6df3c15a1dd4ebd45bc46bb8f3e9 X-Git-Newrev: 8960a29b18b830ff0490b7f52051903fba472e45 Message-Id: <20210830212728.6F42D3858404@sourceware.org> Date: Mon, 30 Aug 2021 21:27:28 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Aug 2021 21:27:28 -0000 https://gcc.gnu.org/g:8960a29b18b830ff0490b7f52051903fba472e45 commit r12-3236-g8960a29b18b830ff0490b7f52051903fba472e45 Author: Jason Merrill Date: Sun Aug 29 18:17:22 2021 -0400 c++: limit instantiation with ill-formed class [PR96286] I noticed that after the static_assert failures in lwg3466.cc, we got various follow-on errors because we went ahead and tried to instantiate the promise member functions even after instantiating the class itself ran into problems. Interrupting instantiation of the class itself seems likely to cause error-recovery problems, but preventing instantiation of member functions seems strictly better for error-recovery. This doesn't fix any of the specific testcases in PR96286, but addresses part of that problem space. PR c++/96286 gcc/cp/ChangeLog: * cp-tree.h (struct lang_type): Add erroneous bit-field. (CLASSTYPE_ERRONEOUS): New. * pt.c (limit_bad_template_recursion): Check it. (instantiate_class_template_1): Set it. libstdc++-v3/ChangeLog: * testsuite/30_threads/promise/requirements/lwg3466.cc: Remove dg-prune-outputs. gcc/testsuite/ChangeLog: * g++.dg/template/access2.C: Split struct A. Diff: --- gcc/cp/cp-tree.h | 7 ++++++- gcc/cp/pt.c | 14 +++++++++++++- gcc/testsuite/g++.dg/template/access2.C | 6 +++++- .../testsuite/30_threads/promise/requirements/lwg3466.cc | 4 ---- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6a179375a56..ce7ca53a113 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2336,6 +2336,7 @@ struct GTY(()) lang_type { unsigned has_constexpr_ctor : 1; unsigned unique_obj_representations : 1; unsigned unique_obj_representations_set : 1; + bool erroneous : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -2344,7 +2345,7 @@ struct GTY(()) lang_type { /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 5; + unsigned dummy : 4; tree primary_base; vec *vcall_indices; @@ -2660,6 +2661,10 @@ struct GTY(()) lang_type { /* Nonzero if a _DECL node requires us to output debug info for this class. */ #define CLASSTYPE_DEBUG_REQUESTED(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->debug_requested) + +/* True if we saw errors while instantiating this class. */ +#define CLASSTYPE_ERRONEOUS(NODE) \ + (LANG_TYPE_CLASS_CHECK (NODE)->erroneous) /* Additional macros for inheritance information. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d7d0dce691c..fcf3ac31b25 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10885,9 +10885,14 @@ limit_bad_template_recursion (tree decl) { struct tinst_level *lev = current_tinst_level; int errs = errorcount + sorrycount; - if (lev == NULL || errs == 0 || !neglectable_inst_p (decl)) + if (errs == 0 || !neglectable_inst_p (decl)) return false; + /* Avoid instantiating members of an ill-formed class. */ + if (DECL_CLASS_SCOPE_P (decl) + && CLASSTYPE_ERRONEOUS (DECL_CONTEXT (decl))) + return true; + for (; lev; lev = lev->next) if (neglectable_inst_p (lev->maybe_get_node ())) break; @@ -12212,6 +12217,13 @@ instantiate_class_template_1 (tree type) finish_struct_1 (type); TYPE_BEING_DEFINED (type) = 0; + /* Remember if instantiating this class ran into errors, so we can avoid + instantiating member functions in limit_bad_template_recursion. We set + this flag even if the problem was in another instantiation triggered by + this one, as that will likely also cause trouble for member functions. */ + if (errorcount + sorrycount > current_tinst_level->errors) + CLASSTYPE_ERRONEOUS (type) = true; + /* We don't instantiate default arguments for member functions. 14.7.1: The implicit instantiation of a class template specialization causes diff --git a/gcc/testsuite/g++.dg/template/access2.C b/gcc/testsuite/g++.dg/template/access2.C index 0620c10f79d..4a80bb4d280 100644 --- a/gcc/testsuite/g++.dg/template/access2.C +++ b/gcc/testsuite/g++.dg/template/access2.C @@ -5,6 +5,9 @@ template struct A { typename T::X x; // { dg-error "this context" } +}; + +template struct A2 { int f() { return T::i; } // { dg-error "this context" } }; @@ -16,5 +19,6 @@ class B { int main() { A ab; // { dg-message "required" } - ab.f(); // { dg-message "required" } + A2 a2b; + a2b.f(); // { dg-message "required" } } diff --git a/libstdc++-v3/testsuite/30_threads/promise/requirements/lwg3466.cc b/libstdc++-v3/testsuite/30_threads/promise/requirements/lwg3466.cc index bb04bf0737c..acef47f12f3 100644 --- a/libstdc++-v3/testsuite/30_threads/promise/requirements/lwg3466.cc +++ b/libstdc++-v3/testsuite/30_threads/promise/requirements/lwg3466.cc @@ -27,17 +27,13 @@ std::promise good2; std::promise bad; // { dg-error "here" } // { dg-error "result type must not be an array" "" { target *-*-* } 0 } -// { dg-prune-output {request for member '~int \[1\]'} } std::promise bad2; // { dg-error "here" } // { dg-error "result type must not be a function" "" { target *-*-* } 0 } -// { dg-prune-output {'sizeof \(int\(\)\)'} } struct Indestructible { ~Indestructible() = delete; }; std::promise bad3; // { dg-error "here" } // { dg-error "result type must be destructible" "" { target *-*-* } 0 } -// { dg-prune-output {deleted function} } class PrivateDtor { public: PrivateDtor(); private: ~PrivateDtor(); }; std::promise bad4; // { dg-error "here" } -// { dg-prune-output {is private} }