Commit deaae9d7 by Jason Merrill Committed by Jason Merrill

re PR c++/54532 ([C++0x][constexpr] internal error when initializing static…

re PR c++/54532 ([C++0x][constexpr] internal error when initializing static constexpr with pointer to non-static member variable)

	PR c++/54532
	* expr.c (cplus_expand_constant): Do nothing if the class is
	incomplete.
	* semantics.c (reduced_constant_expression_p): Allow PTRMEM_CST.
	* typeck2.c (store_init_value): Use reduced_constant_expression_p.
	* decl.c (maybe_register_incomplete_var): Handle PTRMEM_CST.
	(complete_vars): Likewise.

From-SVN: r196852
parent 766053b3
2013-03-20 Jason Merrill <jason@redhat.com> 2013-03-20 Jason Merrill <jason@redhat.com>
PR c++/54532
* expr.c (cplus_expand_constant): Do nothing if the class is
incomplete.
* semantics.c (reduced_constant_expression_p): Allow PTRMEM_CST.
* typeck2.c (store_init_value): Use reduced_constant_expression_p.
* decl.c (maybe_register_incomplete_var): Handle PTRMEM_CST.
(complete_vars): Likewise.
* name-lookup.c (get_anonymous_namespace_name): Never use * name-lookup.c (get_anonymous_namespace_name): Never use
get_file_function_name. get_file_function_name.
......
...@@ -14018,7 +14018,10 @@ grokmethod (cp_decl_specifier_seq *declspecs, ...@@ -14018,7 +14018,10 @@ grokmethod (cp_decl_specifier_seq *declspecs,
/* VAR is a VAR_DECL. If its type is incomplete, remember VAR so that /* VAR is a VAR_DECL. If its type is incomplete, remember VAR so that
we can lay it out later, when and if its type becomes complete. */ we can lay it out later, when and if its type becomes complete.
Also handle constexpr pointer to member variables where the initializer
is an unlowered PTRMEM_CST because the class isn't complete yet. */
void void
maybe_register_incomplete_var (tree var) maybe_register_incomplete_var (tree var)
...@@ -14043,6 +14046,15 @@ maybe_register_incomplete_var (tree var) ...@@ -14043,6 +14046,15 @@ maybe_register_incomplete_var (tree var)
incomplete_var iv = {var, inner_type}; incomplete_var iv = {var, inner_type};
vec_safe_push (incomplete_vars, iv); vec_safe_push (incomplete_vars, iv);
} }
else if (TYPE_PTRMEM_P (inner_type)
&& DECL_INITIAL (var)
&& TREE_CODE (DECL_INITIAL (var)) == PTRMEM_CST)
{
tree context = TYPE_PTRMEM_CLASS_TYPE (inner_type);
gcc_assert (TYPE_BEING_DEFINED (context));
incomplete_var iv = {var, context};
vec_safe_push (incomplete_vars, iv);
}
} }
} }
...@@ -14062,10 +14074,17 @@ complete_vars (tree type) ...@@ -14062,10 +14074,17 @@ complete_vars (tree type)
{ {
tree var = iv->decl; tree var = iv->decl;
tree type = TREE_TYPE (var); tree type = TREE_TYPE (var);
/* Complete the type of the variable. The VAR_DECL itself
will be laid out in expand_expr. */ if (TYPE_PTRMEM_P (type))
complete_type (type); DECL_INITIAL (var) = cplus_expand_constant (DECL_INITIAL (var));
cp_apply_type_quals_to_decl (cp_type_quals (type), var); else
{
/* Complete the type of the variable. The VAR_DECL itself
will be laid out in expand_expr. */
complete_type (type);
cp_apply_type_quals_to_decl (cp_type_quals (type), var);
}
/* Remove this entry from the list. */ /* Remove this entry from the list. */
incomplete_vars->unordered_remove (ix); incomplete_vars->unordered_remove (ix);
} }
......
...@@ -43,6 +43,10 @@ cplus_expand_constant (tree cst) ...@@ -43,6 +43,10 @@ cplus_expand_constant (tree cst)
/* Find the member. */ /* Find the member. */
member = PTRMEM_CST_MEMBER (cst); member = PTRMEM_CST_MEMBER (cst);
/* We can't lower this until the class is complete. */
if (!COMPLETE_TYPE_P (DECL_CONTEXT (member)))
return cst;
if (TREE_CODE (member) == FIELD_DECL) if (TREE_CODE (member) == FIELD_DECL)
{ {
/* Find the offset for the field. */ /* Find the offset for the field. */
......
...@@ -6838,6 +6838,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6838,6 +6838,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
bool bool
reduced_constant_expression_p (tree t) reduced_constant_expression_p (tree t)
{ {
if (TREE_CODE (t) == PTRMEM_CST)
/* Even if we can't lower this yet, it's constant. */
return true;
/* FIXME are we calling this too much? */ /* FIXME are we calling this too much? */
return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE; return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
} }
......
...@@ -792,7 +792,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) ...@@ -792,7 +792,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
will perform the dynamic initialization. */ will perform the dynamic initialization. */
if (value != error_mark_node if (value != error_mark_node
&& (TREE_SIDE_EFFECTS (value) && (TREE_SIDE_EFFECTS (value)
|| ! initializer_constant_valid_p (value, TREE_TYPE (value)))) || ! reduced_constant_expression_p (value)))
{ {
if (TREE_CODE (type) == ARRAY_TYPE if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))) && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
......
// PR c++/54532
// { dg-do compile { target c++11 } }
#define SA(X) static_assert(X,#X)
struct A {
int i;
constexpr static int A::*p = &A::i;
};
constexpr A a = { 42 };
SA(a.*A::p == 42);
constexpr int A::* A::p;
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