Commit aef4a215 by Jason Merrill Committed by Jason Merrill

decl2.c (decl_constant_var_p): New fn.

	* decl2.c (decl_constant_var_p): New fn.
	(decl_maybe_constant_var_p): New fn.
	(mark_used): Rework instantiation of things needed for constant
	expressions.
	* cp-tree.h: Declare new fns.
	* pt.c (instantiate_decl): Handle cp_unevaluated_operand.
	(always_instantiate_p): Use decl_maybe_constant_var_p.
	(instantiate_decl): Don't defer constexpr functions.
	* repo.c (repo_emit_p): Use decl_maybe_constant_var_p.
	* semantics.c (finish_id_expression): Use decl_constant_var_p.
	Check for valid name in constant expr after mark_used.

From-SVN: r166164
parent 7bf8ca76
2010-11-01 Jason Merrill <jason@redhat.com>
* decl2.c (decl_constant_var_p): New fn.
(decl_maybe_constant_var_p): New fn.
(mark_used): Rework instantiation of things needed for constant
expressions.
* cp-tree.h: Declare new fns.
* pt.c (instantiate_decl): Handle cp_unevaluated_operand.
(always_instantiate_p): Use decl_maybe_constant_var_p.
(instantiate_decl): Don't defer constexpr functions.
* repo.c (repo_emit_p): Use decl_maybe_constant_var_p.
* semantics.c (finish_id_expression): Use decl_constant_var_p.
Check for valid name in constant expr after mark_used.
2010-10-31 Jason Merrill <jason@redhat.com> 2010-10-31 Jason Merrill <jason@redhat.com>
* class.c (is_really_empty_class): Work when type is not complete. * class.c (is_really_empty_class): Work when type is not complete.
......
...@@ -4882,6 +4882,8 @@ extern void constrain_class_visibility (tree); ...@@ -4882,6 +4882,8 @@ extern void constrain_class_visibility (tree);
extern void import_export_decl (tree); extern void import_export_decl (tree);
extern tree build_cleanup (tree); extern tree build_cleanup (tree);
extern tree build_offset_ref_call_from_tree (tree, VEC(tree,gc) **); extern tree build_offset_ref_call_from_tree (tree, VEC(tree,gc) **);
extern bool decl_constant_var_p (tree);
extern bool decl_maybe_constant_var_p (tree);
extern void check_default_args (tree); extern void check_default_args (tree);
extern void mark_used (tree); extern void mark_used (tree);
extern void finish_static_data_member_decl (tree, tree, bool, tree, int); extern void finish_static_data_member_decl (tree, tree, bool, tree, int);
......
...@@ -3526,6 +3526,60 @@ decl_defined_p (tree decl) ...@@ -3526,6 +3526,60 @@ decl_defined_p (tree decl)
} }
} }
/* Nonzero for a VAR_DECL whose value can be used in a constant expression.
[expr.const]
An integral constant-expression can only involve ... const
variables of integral or enumeration types initialized with
constant expressions ...
C++0x also allows constexpr variables and temporaries initialized
with constant expressions. We handle the former here, but the latter
are just folded away in cxx_eval_constant_expression.
The standard does not require that the expression be non-volatile.
G++ implements the proposed correction in DR 457. */
bool
decl_constant_var_p (tree decl)
{
bool ret;
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) != VAR_DECL)
return false;
if (DECL_DECLARED_CONSTEXPR_P (decl))
ret = true;
else if (CP_TYPE_CONST_NON_VOLATILE_P (type)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
/* We don't know if a template static data member is initialized with
a constant expression until we instantiate its initializer. */
mark_used (decl);
ret = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl);
}
else
ret = false;
gcc_assert (!ret || DECL_INITIAL (decl));
return ret;
}
/* Returns true if DECL could be a symbolic constant variable, depending on
its initializer. */
bool
decl_maybe_constant_var_p (tree decl)
{
tree type = TREE_TYPE (decl);
if (TREE_CODE (decl) != VAR_DECL)
return false;
if (DECL_DECLARED_CONSTEXPR_P (decl))
return true;
return (CP_TYPE_CONST_NON_VOLATILE_P (type)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (type));
}
/* Complain that DECL uses a type with no linkage but is never defined. */ /* Complain that DECL uses a type with no linkage but is never defined. */
static void static void
...@@ -4074,8 +4128,6 @@ possibly_inlined_p (tree decl) ...@@ -4074,8 +4128,6 @@ possibly_inlined_p (tree decl)
void void
mark_used (tree decl) mark_used (tree decl)
{ {
HOST_WIDE_INT saved_processing_template_decl = 0;
/* If DECL is a BASELINK for a single function, then treat it just /* If DECL is a BASELINK for a single function, then treat it just
like the DECL for the function. Otherwise, if the BASELINK is like the DECL for the function. Otherwise, if the BASELINK is
for an overloaded function, we don't know which function was for an overloaded function, we don't know which function was
...@@ -4113,9 +4165,6 @@ mark_used (tree decl) ...@@ -4113,9 +4165,6 @@ mark_used (tree decl)
error_at (DECL_SOURCE_LOCATION (decl), "declared here"); error_at (DECL_SOURCE_LOCATION (decl), "declared here");
return; return;
} }
/* If we don't need a value, then we don't need to synthesize DECL. */
if (cp_unevaluated_operand != 0)
return;
/* We can only check DECL_ODR_USED on variables or functions with /* We can only check DECL_ODR_USED on variables or functions with
DECL_LANG_SPECIFIC set, and these are also the only decls that we DECL_LANG_SPECIFIC set, and these are also the only decls that we
...@@ -4139,31 +4188,39 @@ mark_used (tree decl) ...@@ -4139,31 +4188,39 @@ mark_used (tree decl)
return; return;
} }
/* Normally, we can wait until instantiation-time to synthesize /* Normally, we can wait until instantiation-time to synthesize DECL.
DECL. However, if DECL is a static data member initialized with However, if DECL is a static data member initialized with a constant
a constant, we need the value right now because a reference to or a constexpr function, we need it right now because a reference to
such a data member is not value-dependent. */ such a data member or a call to such function is not value-dependent. */
if (TREE_CODE (decl) == VAR_DECL if ((decl_maybe_constant_var_p (decl)
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) || (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_CLASS_SCOPE_P (decl)) && DECL_DECLARED_CONSTEXPR_P (decl)))
&& !DECL_INITIAL (decl)
&& DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INSTANTIATION (decl))
{ {
/* Don't try to instantiate members of dependent types. We /* Instantiating a function will result in garbage collection. We
cannot just use dependent_type_p here because this function must treat this situation as if we were within the body of a
may be called from fold_non_dependent_expr, and then we may function so as to avoid collecting live data only referenced from
see dependent types, even though processing_template_decl the stack (such as overload resolution candidates). */
will not be set. */ ++function_depth;
if (CLASSTYPE_TEMPLATE_INFO ((DECL_CONTEXT (decl))) instantiate_decl (decl, /*defer_ok=*/false,
&& uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl)))) /*expl_inst_class_mem_p=*/false);
return; --function_depth;
/* Pretend that we are not in a template, even if we are, so
that the static data member initializer will be processed. */
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
} }
/* If we don't need a value, then we don't need to synthesize DECL. */
if (cp_unevaluated_operand != 0)
return;
if (processing_template_decl) if (processing_template_decl)
return; return;
/* Check this too in case we're within fold_non_dependent_expr. */
if (DECL_TEMPLATE_INFO (decl)
&& uses_template_parms (DECL_TI_ARGS (decl)))
return;
DECL_ODR_USED (decl) = 1; DECL_ODR_USED (decl) = 1;
if (DECL_CLONED_FUNCTION_P (decl)) if (DECL_CLONED_FUNCTION_P (decl))
DECL_ODR_USED (DECL_CLONED_FUNCTION (decl)) = 1; DECL_ODR_USED (DECL_CLONED_FUNCTION (decl)) = 1;
...@@ -4233,8 +4290,6 @@ mark_used (tree decl) ...@@ -4233,8 +4290,6 @@ mark_used (tree decl)
need. Therefore, we always try to defer instantiation. */ need. Therefore, we always try to defer instantiation. */
instantiate_decl (decl, /*defer_ok=*/true, instantiate_decl (decl, /*defer_ok=*/true,
/*expl_inst_class_mem_p=*/false); /*expl_inst_class_mem_p=*/false);
processing_template_decl = saved_processing_template_decl;
} }
#include "gt-cp-decl2.h" #include "gt-cp-decl2.h"
...@@ -16714,7 +16714,7 @@ always_instantiate_p (tree decl) ...@@ -16714,7 +16714,7 @@ always_instantiate_p (tree decl)
their initializers are available in integral constant their initializers are available in integral constant
expressions. */ expressions. */
|| (TREE_CODE (decl) == VAR_DECL || (TREE_CODE (decl) == VAR_DECL
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))); && decl_maybe_constant_var_p (decl)));
} }
/* Produce the definition of D, a _DECL generated from a template. If /* Produce the definition of D, a _DECL generated from a template. If
...@@ -16750,7 +16750,8 @@ instantiate_decl (tree d, int defer_ok, ...@@ -16750,7 +16750,8 @@ instantiate_decl (tree d, int defer_ok,
case that an expression refers to the value of the variable -- case that an expression refers to the value of the variable --
if the variable has a constant value the referring expression can if the variable has a constant value the referring expression can
take advantage of that fact. */ take advantage of that fact. */
if (TREE_CODE (d) == VAR_DECL) if (TREE_CODE (d) == VAR_DECL
|| DECL_DECLARED_CONSTEXPR_P (d))
defer_ok = 0; defer_ok = 0;
/* Don't instantiate cloned functions. Instead, instantiate the /* Don't instantiate cloned functions. Instead, instantiate the
...@@ -16926,6 +16927,11 @@ instantiate_decl (tree d, int defer_ok, ...@@ -16926,6 +16927,11 @@ instantiate_decl (tree d, int defer_ok,
permerror (input_location, "explicit instantiation of %qD " permerror (input_location, "explicit instantiation of %qD "
"but no definition available", d); "but no definition available", d);
/* If we're in unevaluated context, we just wanted to get the
constant value; this isn't an odr use, so don't queue
a full instantiation. */
if (cp_unevaluated_operand != 0)
goto out;
/* ??? Historically, we have instantiated inline functions, even /* ??? Historically, we have instantiated inline functions, even
when marked as "extern template". */ when marked as "extern template". */
if (!(external_p && TREE_CODE (d) == VAR_DECL)) if (!(external_p && TREE_CODE (d) == VAR_DECL))
......
...@@ -319,7 +319,7 @@ repo_emit_p (tree decl) ...@@ -319,7 +319,7 @@ repo_emit_p (tree decl)
available. Still record them into *.rpo files, so if they available. Still record them into *.rpo files, so if they
weren't actually emitted and collect2 requests them, they can weren't actually emitted and collect2 requests them, they can
be provided. */ be provided. */
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl) if (decl_maybe_constant_var_p (decl)
&& DECL_CLASS_SCOPE_P (decl)) && DECL_CLASS_SCOPE_P (decl))
ret = 2; ret = 2;
} }
......
...@@ -2826,7 +2826,7 @@ finish_id_expression (tree id_expression, ...@@ -2826,7 +2826,7 @@ finish_id_expression (tree id_expression,
the complexity of the problem" the complexity of the problem"
FIXME update for final resolution of core issue 696. */ FIXME update for final resolution of core issue 696. */
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) if (decl_constant_var_p (decl))
return integral_constant_value (decl); return integral_constant_value (decl);
if (TYPE_P (context)) if (TYPE_P (context))
...@@ -3077,21 +3077,6 @@ finish_id_expression (tree id_expression, ...@@ -3077,21 +3077,6 @@ finish_id_expression (tree id_expression,
return id_expression; return id_expression;
} }
/* Only certain kinds of names are allowed in constant
expression. Enumerators and template parameters have already
been handled above. */
if (integral_constant_expression_p
&& ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
&& ! builtin_valid_in_constant_expr_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
error ("%qD cannot appear in a constant-expression", decl);
return error_mark_node;
}
*non_integral_constant_expression_p = true;
}
if (TREE_CODE (decl) == NAMESPACE_DECL) if (TREE_CODE (decl) == NAMESPACE_DECL)
{ {
error ("use of namespace %qD as expression", decl); error ("use of namespace %qD as expression", decl);
...@@ -3118,6 +3103,21 @@ finish_id_expression (tree id_expression, ...@@ -3118,6 +3103,21 @@ finish_id_expression (tree id_expression,
|| TREE_CODE (decl) == RESULT_DECL) || TREE_CODE (decl) == RESULT_DECL)
mark_used (decl); mark_used (decl);
/* Only certain kinds of names are allowed in constant
expression. Enumerators and template parameters have already
been handled above. */
if (integral_constant_expression_p
&& ! decl_constant_var_p (decl)
&& ! builtin_valid_in_constant_expr_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
error ("%qD cannot appear in a constant-expression", decl);
return error_mark_node;
}
*non_integral_constant_expression_p = true;
}
if (scope) if (scope)
{ {
decl = (adjust_result_of_qualified_name_lookup decl = (adjust_result_of_qualified_name_lookup
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment