re PR c++/56041 (Constexpr conversion function definition not found in template argum...
authorJason Merrill <jason@redhat.com>
Thu, 20 Nov 2014 03:25:26 +0000 (22:25 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 20 Nov 2014 03:25:26 +0000 (22:25 -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.

From-SVN: r217823

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/constexpr-conv1.C [new file with mode: 0644]

index 8f21d8b114699a5585c1a64fdc3f8b6b144b4dcf..09781410a19cb58168aaa22e2c0a2a789b902b52 100644 (file)
@@ -1,5 +1,12 @@
 2014-11-19  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        PR c++/63885
        * constexpr.c (cxx_eval_constant_expression) [PARM_DECL]: Don't
        complain yet about a reference.
index 41867b8dc287dac25579492ecda1e85b192bcbb5..2678223a6038618cbd0d00786bb058ffc9e1d616 100644 (file)
@@ -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))
index 1e09629b4afa365907a4d65bd7b9c0d3fc9cb8b1..b3781ab7a72aee25dc7ee40696d0f108b6903bcb 100644 (file)
@@ -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);
index 0b8fd7fd37f168717ba64bc7cd0415f0a84bdd75..05ca70628658e3dd6fb5bd3459869dfad9589860 100644 (file)
@@ -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 (file)
index 0000000..fd34f23
--- /dev/null
@@ -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>();
+}