public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
From: Jason Merrill <jason@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org
Subject: [gcc r12-3236] c++: limit instantiation with ill-formed class [PR96286]
Date: Mon, 30 Aug 2021 21:27:28 +0000 (GMT)	[thread overview]
Message-ID: <20210830212728.6F42D3858404@sourceware.org> (raw)

https://gcc.gnu.org/g:8960a29b18b830ff0490b7f52051903fba472e45

commit r12-3236-g8960a29b18b830ff0490b7f52051903fba472e45
Author: Jason Merrill <jason@redhat.com>
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<T> 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<tree_pair_s, va_gc> *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)
 \f
 /* 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 <class T> struct A {
   typename T::X x;			// { dg-error "this context" }
+};
+
+template <class T> struct A2 {
   int f() { return T::i; }		// { dg-error "this context" }
 };
 
@@ -16,5 +19,6 @@ class B {
 int main()
 {
   A<B> ab;				// { dg-message "required" }
-  ab.f();				// { dg-message "required" }
+  A2<B> 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<int(&)()> good2;
 
 std::promise<int[1]> 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<int()> 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<Indestructible> 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<PrivateDtor> bad4; // { dg-error "here" }
-// { dg-prune-output {is private} }


                 reply	other threads:[~2021-08-30 21:27 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210830212728.6F42D3858404@sourceware.org \
    --to=jason@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    --cc=libstdc++-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).