diff mbox

C++ PATCH for c++/56041 (conversion of non-type template argument)

Message ID 546D5F11.4070802@redhat.com
State New
Headers show

Commit Message

Jason Merrill Nov. 20, 2014, 3:25 a.m. UTC
In this testcase, the problem was that we were instantiating the 
non-dependent template argument but then trying to perform conversions 
on it back in the template context, so we got a confusion of template 
and non-template trees.  This patch changes convert_nontype_argument to 
leave processing_template_decl cleared while we do conversions.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit aa18329f47f536350fea2d5de785fc71ad0429f1
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Nov 17 16:58:32 2014 -0500

    	PR c++/56041
    	* cp-tree.h (struct processing_template_decl_sentinel): New.
    	* pt.c (instantiate_non_dependent_expr_internal): Split out from...
    	(instantiate_non_dependent_expr_sfinae): Here.
    	(convert_nontype_argument): Use them.
    	* constexpr.c (fold_non_dependent_expr): Use them.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 41867b8..2678223 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3506,17 +3506,8 @@  fold_non_dependent_expr (tree t)
       if (!instantiation_dependent_expression_p (t)
 	  && potential_constant_expression (t))
 	{
-	  HOST_WIDE_INT saved_processing_template_decl;
-
-	  saved_processing_template_decl = processing_template_decl;
-	  processing_template_decl = 0;
-	  t = tsubst_copy_and_build (t,
-				     /*args=*/NULL_TREE,
-				     tf_none,
-				     /*in_decl=*/NULL_TREE,
-				     /*function_p=*/false,
-				     /*integral_constant_expression_p=*/true);
-	  processing_template_decl = saved_processing_template_decl;
+	  processing_template_decl_sentinel s;
+	  t = instantiate_non_dependent_expr_internal (t, tf_none);
 
 	  if (type_unknown_p (t)
 	      || BRACE_ENCLOSED_INITIALIZER_P (t))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1e09629..b3781ab 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1082,6 +1082,8 @@  struct GTY(()) saved_scope {
   struct saved_scope *prev;
 };
 
+extern GTY(()) struct saved_scope *scope_chain;
+
 /* The current open namespace.  */
 
 #define current_namespace scope_chain->old_namespace
@@ -1123,6 +1125,24 @@  struct GTY(()) saved_scope {
 #define processing_specialization scope_chain->x_processing_specialization
 #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
 
+/* RAII sentinel to handle clearing processing_template_decl and restoring
+   it when done.  */
+
+struct processing_template_decl_sentinel
+{
+  int saved;
+  processing_template_decl_sentinel (bool reset = true)
+    : saved (processing_template_decl)
+  {
+    if (reset)
+      processing_template_decl = 0;
+  }
+  ~processing_template_decl_sentinel()
+  {
+    processing_template_decl = saved;
+  }
+};
+
 /* The cached class binding level, from the most recently exited
    class, or NULL if none.  */
 
@@ -1140,8 +1160,6 @@  struct GTY(()) saved_scope {
 
 /* A list of private types mentioned, for deferred access checking.  */
 
-extern GTY(()) struct saved_scope *scope_chain;
-
 struct GTY((for_user)) cxx_int_tree_map {
   unsigned int uid;
   tree to;
@@ -5716,6 +5734,7 @@  extern void make_args_non_dependent		(vec<tree, va_gc> *);
 extern bool reregister_specialization		(tree, tree, tree);
 extern tree instantiate_non_dependent_expr	(tree);
 extern tree instantiate_non_dependent_expr_sfinae (tree, tsubst_flags_t);
+extern tree instantiate_non_dependent_expr_internal (tree, tsubst_flags_t);
 extern bool alias_type_or_template_p            (tree);
 extern bool alias_template_specialization_p     (const_tree);
 extern bool dependent_alias_template_spec_p     (const_tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0b8fd7f..05ca706 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5212,6 +5212,24 @@  redeclare_class_template (tree type, tree parms)
     return true;
 }
 
+/* The actual substitution part of instantiate_non_dependent_expr_sfinae,
+   to be used when the caller has already checked
+   (processing_template_decl
+    && !instantiation_dependent_expression_p (expr)
+    && potential_constant_expression (expr))
+   and cleared processing_template_decl.  */
+
+tree
+instantiate_non_dependent_expr_internal (tree expr, tsubst_flags_t complain)
+{
+  return tsubst_copy_and_build (expr,
+				/*args=*/NULL_TREE,
+				complain,
+				/*in_decl=*/NULL_TREE,
+				/*function_p=*/false,
+				/*integral_constant_expression_p=*/true);
+}
+
 /* Simplify EXPR if it is a non-dependent expression.  Returns the
    (possibly simplified) expression.  */
 
@@ -5232,17 +5250,8 @@  instantiate_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
       && !instantiation_dependent_expression_p (expr)
       && potential_constant_expression (expr))
     {
-      HOST_WIDE_INT saved_processing_template_decl;
-
-      saved_processing_template_decl = processing_template_decl;
-      processing_template_decl = 0;
-      expr = tsubst_copy_and_build (expr,
-				    /*args=*/NULL_TREE,
-				    complain,
-				    /*in_decl=*/NULL_TREE,
-				    /*function_p=*/false,
-				    /*integral_constant_expression_p=*/true);
-      processing_template_decl = saved_processing_template_decl;
+      processing_template_decl_sentinel s;
+      expr = instantiate_non_dependent_expr_internal (expr, complain);
     }
   return expr;
 }
@@ -5736,11 +5745,15 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
      so that access checking can be performed when the template is
      instantiated -- but here we need the resolved form so that we can
      convert the argument.  */
+  bool non_dep = false;
   if (TYPE_REF_OBJ_P (type)
       && has_value_dependent_address (expr))
     /* If we want the address and it's value-dependent, don't fold.  */;
-  else if (!type_unknown_p (expr))
-    expr = instantiate_non_dependent_expr_sfinae (expr, complain);
+  else if (!type_unknown_p (expr)
+	   && processing_template_decl
+	   && !instantiation_dependent_expression_p (expr)
+	   && potential_constant_expression (expr))
+    non_dep = true;
   if (error_operand_p (expr))
     return error_mark_node;
   expr_type = TREE_TYPE (expr);
@@ -5749,6 +5762,12 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   else
     expr = mark_rvalue_use (expr);
 
+  /* If the argument is non-dependent, perform any conversions in
+     non-dependent context as well.  */
+  processing_template_decl_sentinel s (non_dep);
+  if (non_dep)
+    expr = instantiate_non_dependent_expr_internal (expr, complain);
+
   /* 14.3.2/5: The null pointer{,-to-member} conversion is applied
      to a non-type argument of "nullptr".  */
   if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C
new file mode 100644
index 0000000..fd34f23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C
@@ -0,0 +1,34 @@ 
+// PR c++/56041
+// { dg-do compile { target c++11 } }
+
+template< class T, T v >
+struct integral_constant
+{
+  using type       = integral_constant<T,v>;
+  using value_type = T;
+  static constexpr T value  = v;
+  constexpr operator T  ( )  noexcept { return value; }
+};
+
+using true_type  = integral_constant<bool, true>;
+using false_type = integral_constant<bool, false>;
+
+template< bool b, class T = void >  struct enable_if  { using type = T; };
+template< class T >                 struct enable_if<false, T>  { };
+
+
+template< class T,
+	  class = typename enable_if< true_type{}       // should compile; doesn't
+				      , T>::type
+	  >
+T try_it( )  { return T{}; }
+
+int main( )
+{
+  static_assert( true_type{}     , "failed test 1!" );
+  static_assert( true_type{}     , "failed test 2!" );
+  static_assert( ! false_type{}  , "failed test 3!" );
+  static_assert( !! true_type{}  , "failed test 4!" );
+
+  return try_it<int>();
+}