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.
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))
struct saved_scope *prev;
};
+extern GTY(()) struct saved_scope *scope_chain;
+
/* The current open namespace. */
#define current_namespace scope_chain->old_namespace
#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. */
/* 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;
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);
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. */
&& !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;
}
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);
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))
--- /dev/null
+// 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>();
+}