C++ PATCH for c++/84296, ICE with qualified-id

Message ID CADzB+2=a4wG+Kccj_siZ+mft8Sx=FwELeRCuW83K=L3U=niZEQ@mail.gmail.com
State New
Headers show
Series
  • C++ PATCH for c++/84296, ICE with qualified-id
Related show

Commit Message

Jason Merrill Feb. 9, 2018, 7:09 p.m.
In my patch to fix template/inherit4.C after 83714, I made all
SCOPE_REFs instantiation-dependent if the current class has dependent
bases.  This was excessive; only a reference to a non-static member of
an unknown base needs to be treated as instantiation-dependent.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 6d409191cfcd993863e791672ae6de78444796b1
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 9 13:31:27 2018 -0500

            PR c++/84296 - ICE with qualified-id in template.
    
            PR c++/83714
            * pt.c (unknown_base_ref_p): New.
            (instantiation_dependent_scope_ref_p): Use it instead of
            any_dependent_bases_p.

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a9e47701527..9c57709e7a7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -24012,6 +24012,30 @@  dependent_scope_p (tree scope)
 	  && !currently_open_class (scope));
 }
 
+/* T is a SCOPE_REF.  Return whether it represents a non-static member of
+   an unknown base of 'this' (and is therefore instantiation-dependent).  */
+
+static bool
+unknown_base_ref_p (tree t)
+{
+  if (!current_class_ptr)
+    return false;
+
+  tree mem = TREE_OPERAND (t, 1);
+  if (shared_member_p (mem))
+    return false;
+
+  tree cur = current_nonlambda_class_type ();
+  if (!any_dependent_bases_p (cur))
+    return false;
+
+  tree ctx = TREE_OPERAND (t, 0);
+  if (DERIVED_FROM_P (ctx, cur))
+    return false;
+
+  return true;
+}
+
 /* T is a SCOPE_REF; return whether we need to consider it
     instantiation-dependent so that we can check access at instantiation
     time even though we know which member it resolves to.  */
@@ -24021,9 +24045,7 @@  instantiation_dependent_scope_ref_p (tree t)
 {
   if (DECL_P (TREE_OPERAND (t, 1))
       && CLASS_TYPE_P (TREE_OPERAND (t, 0))
-      /* A dependent base could make a member inaccessible in the current
-	 class.  */
-      && !any_dependent_bases_p ()
+      && !unknown_base_ref_p (t)
       && accessible_in_template_p (TREE_OPERAND (t, 0),
 				   TREE_OPERAND (t, 1)))
     return false;
diff --git a/gcc/testsuite/g++.dg/template/scope5.C b/gcc/testsuite/g++.dg/template/scope5.C
new file mode 100644
index 00000000000..629225cd556
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/scope5.C
@@ -0,0 +1,66 @@ 
+// PR c++/84296
+
+namespace b {}
+namespace c {
+using namespace b;
+}
+namespace b {
+template <int d> struct e { static const int f = d; };
+}
+template <typename> struct g;
+template <typename h, typename i, typename aa, typename j>
+struct g<h(i, aa, j)> : h::template ab<i, aa, j> {};
+struct k {
+  template <typename l> struct m { typedef typename g<l>::n o; };
+};
+template <typename> struct ac;
+struct r {
+  typedef ac<int> p;
+};
+template <typename q> struct s : k {
+  template <typename i, typename, typename>
+  struct ab : q::template t<typename i::u>::template ab<i, int, int> {};
+};
+struct ad {
+  typedef int u;
+};
+template <typename> struct ae;
+template <typename, typename ag> struct ah {
+  typedef ae<ag> ai;
+  typedef typename ai::template w<ai(r, int)>::o n;
+};
+struct x {
+  template <typename i, typename, typename> struct ab : ah<i, int> {};
+};
+struct y {
+  struct z {
+    template <typename> struct t : x {};
+  };
+  struct aj : s<z> {};
+};
+template <typename i> struct ak {
+  typedef y::aj al;
+  typedef typename al::m<al(i, int, int)>::o o;
+};
+struct am {
+  enum { an };
+};
+template <typename> struct ao {};
+template <typename af> struct ap : af::aq {};
+template <> struct ae<int> {
+  template <typename> struct w;
+  template <typename ar, typename as, typename at> struct w<ar(as, at)> {
+    typedef typename as::p o;
+  };
+};
+enum { a = b::e<0>::f };
+template <typename> class au;
+template <typename av> struct ac : ao<av> { typedef c::e<am::an> aq; };
+template <typename aw, typename i, typename ax> void ay(aw, i, ax) {
+  au<c::e<ap<typename ak<i>::o>::f> > az();
+}
+void v() {
+  ad a;
+  void az();
+  ay(az, a, v);
+}