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
This commit is contained in:
Jason Merrill 2010-11-01 21:30:39 -04:00 committed by Jason Merrill
parent 7bf8ca763d
commit aef4a21519
6 changed files with 122 additions and 45 deletions

View File

@ -1,3 +1,17 @@
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.

View File

@ -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);

View File

@ -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)
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)
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)
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)
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"

View File

@ -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,
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,
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))

View File

@ -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;
} }

View File

@ -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,
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,
|| 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