While a class is still being defined, we don't know the offsets of the
members, so a pointer-to-member expression can't be lowered to an
integer, it needs to stay as a PTRMEM_CST. But it's still a constant as
far as the language is concerned, so we need to allow it and then lower
it when the class is complete.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit c41c286c3b13d1d1b3831fab38497146bd0c2f8b
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Feb 15 16:25:27 2013 -0500
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.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index facaae7..4ccb541 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -14018,7 +14018,10 @@ grokmethod (cp_decl_specifier_seq *declspecs,
/* 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
maybe_register_incomplete_var (tree var)
@@ -14043,6 +14046,15 @@ maybe_register_incomplete_var (tree var)
incomplete_var iv = {var, inner_type};
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)
{
tree var = iv->decl;
tree type = TREE_TYPE (var);
- /* 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);
+
+ if (TYPE_PTRMEM_P (type))
+ DECL_INITIAL (var) = cplus_expand_constant (DECL_INITIAL (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. */
incomplete_vars->unordered_remove (ix);
}
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index ffd18ca..f15b049 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -43,6 +43,10 @@ cplus_expand_constant (tree cst)
/* Find the member. */
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)
{
/* Find the offset for the field. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5143e4b..3691d86 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -6838,6 +6838,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
bool
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? */
return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE;
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 3bac67c..6ef46a1 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -792,7 +792,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
will perform the dynamic initialization. */
if (value != error_mark_node
&& (TREE_SIDE_EFFECTS (value)
- || ! initializer_constant_valid_p (value, TREE_TYPE (value))))
+ || ! reduced_constant_expression_p (value)))
{
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C
new file mode 100644
index 0000000..91cc25a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-static11.C
@@ -0,0 +1,14 @@
+// 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;