Patchwork C++ PATCH for c++/54575 (ICE with alias template)

login
register
mail settings
Submitter Jason Merrill
Date Sept. 18, 2012, 3:39 a.m.
Message ID <5057ED03.7000107@redhat.com>
Download mbox | patch
Permalink /patch/184600/
State New
Headers show

Comments

Jason Merrill - Sept. 18, 2012, 3:39 a.m.
The change to make SCOPE_REFs value-dependent revealed a bug in our 
handling of alias-template instantiations; we weren't pushing into the 
context of the alias before substituting the type, and then we were 
remembering the previously instantiated one when instantiating in a 
different context.  If the difference in context makes a difference, for 
instance in access control, this is broken.

There are two possible ways to fix this: either push into the context of 
the alias or don't remember instantiations.  EDG takes the former 
approach, clang the latter.  I've raised the issue with the committee, 
but for the moment I'm following the EDG approach.

Tested x86_64-pc-linux-gnu, applying to trunk.
Gabriel Dos Reis - Sept. 18, 2012, 5:22 a.m.
On Mon, Sep 17, 2012 at 10:39 PM, Jason Merrill <jason@redhat.com> wrote:
> The change to make SCOPE_REFs value-dependent revealed a bug in our handling
> of alias-template instantiations; we weren't pushing into the context of the
> alias before substituting the type, and then we were remembering the
> previously instantiated one when instantiating in a different context.  If
> the difference in context makes a difference, for instance in access
> control, this is broken.
>
> There are two possible ways to fix this: either push into the context of the
> alias or don't remember instantiations.  EDG takes the former approach,
> clang the latter.  I've raised the issue with the committee, but for the
> moment I'm following the EDG approach.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.

I endorse the EDG interpretation.

-- Gaby

Patch

commit 64de00d68f48f64700df3db37ed52ae2d2f8a1b0
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Sep 17 17:29:56 2012 -0400

    	PR c++/54575
    	* pt.c (instantiate_alias_template): New.
    	(tsubst): Use it.
    	(push_access_scope): Allow TYPE_DECL.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7924dff..16952bf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -205,16 +205,18 @@  static tree template_parm_to_arg (tree t);
 static bool arg_from_parm_pack_p (tree, tree);
 static tree current_template_args (void);
 static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
+static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
-   template, or VAR_DECL for static member variable (need by
-   instantiate_decl).  */
+   template, VAR_DECL for static member variable, or TYPE_DECL for
+   alias template (needed by instantiate_decl).  */
 
 static void
 push_access_scope (tree t)
 {
   gcc_assert (TREE_CODE (t) == FUNCTION_DECL
+	      || TREE_CODE (t) == TYPE_DECL
 	      || TREE_CODE (t) == VAR_DECL);
 
   if (DECL_FRIEND_CONTEXT (t))
@@ -10949,10 +10951,10 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	  && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
 	{
 	  /* DECL represents an alias template and we want to
-	     instantiate it.  Let's substitute our arguments for the
-	     template parameters into the declaration and get the
-	     resulting type.  */
-	  r = tsubst (decl, args, complain, decl);
+	     instantiate it.  */
+	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
+	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+	  r = instantiate_alias_template (tmpl, gen_args, complain);
 	}
       else if (DECL_CLASS_SCOPE_P (decl)
 	       && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
@@ -14377,7 +14379,7 @@  recheck_decl_substitution (tree d, tree tmpl, tree args)
   pop_access_scope (d);
 }
 
-/* Instantiate the indicated variable or function template TMPL with
+/* Instantiate the indicated variable, function, or alias template TMPL with
    the template arguments in TARG_PTR.  */
 
 static tree
@@ -14526,6 +14528,35 @@  instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain)
   return ret;
 }
 
+/* Instantiate the alias template TMPL with ARGS.  Also push a template
+   instantiation level, which instantiate_template doesn't do because
+   functions and variables have sufficient context established by the
+   callers.  */
+
+static tree
+instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
+{
+  struct pending_template *old_last_pend = last_pending_template;
+  struct tinst_level *old_error_tinst = last_error_tinst_level;
+  if (tmpl == error_mark_node || args == error_mark_node)
+    return error_mark_node;
+  tree tinst = build_tree_list (tmpl, args);
+  if (!push_tinst_level (tinst))
+    {
+      ggc_free (tinst);
+      return error_mark_node;
+    }
+  tree r = instantiate_template (tmpl, args, complain);
+  pop_tinst_level ();
+  /* We can't free this if a pending_template entry or last_error_tinst_level
+     is pointing at it.  */
+  if (last_pending_template == old_last_pend
+      && last_error_tinst_level == old_error_tinst)
+    ggc_free (tinst);
+
+  return r;
+}
+
 /* PARM is a template parameter pack for FN.  Returns true iff
    PARM is used in a deducible way in the argument list of FN.  */
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-21.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-21.C
new file mode 100644
index 0000000..463f539
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-21.C
@@ -0,0 +1,23 @@ 
+// PR c++/54575
+// { dg-do compile { target c++11 } }
+
+template<typename _From, typename _To>
+struct is_convertible { static const bool value = true; };
+
+template<bool> struct enable_if       { };
+template<>     struct enable_if<true> { typedef int type; };
+
+template<typename _InIter>
+using _RequireInputIter
+= typename enable_if<is_convertible<_InIter,bool>::value>::type;
+
+template<typename _Tp> struct X {
+    template<typename _InputIterator,
+         typename = _RequireInputIter<_InputIterator>>
+      void insert(_InputIterator) {}
+};
+
+template<typename> void foo() {
+  X<int> subdomain_indices;
+  subdomain_indices.insert(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-22.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-22.C
new file mode 100644
index 0000000..1f6cb8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-22.C
@@ -0,0 +1,12 @@ 
+// The standard is unclear about whether this testcase is well-formed.
+// Clang considers it well-formed, EDG not.  Let's go with EDG for now.
+// { dg-do compile { target c++11 } }
+
+template <class T>
+using foo = typename T::bar;	// { dg-error "this context" }
+
+class B
+{
+  typedef int bar;		// { dg-error "private" }
+  foo<B> f;			// { dg-message "required" }
+};