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.
commit aa18329f47f536350fea2d5de785fc71ad0429f1
Author: Jason Merrill <ja...@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>();
+}