From: Jason Merrill Date: Thu, 21 Mar 2013 03:25:35 +0000 (-0400) Subject: re PR c++/54532 ([C++0x][constexpr] internal error when initializing static constexpr... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=deaae9d7c73f87cfd2a0125411fdc54824b5d410;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 719f70c693a..64a085c7fb5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2013-03-20 Jason Merrill + 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 get_file_function_name. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index facaae7ff19..4ccb5414cc6 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 ffd18ca6785..f15b049baf8 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 5143e4bd582..3691d862049 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 3bac67cf119..6ef46a1b00f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -792,7 +792,7 @@ store_init_value (tree decl, tree init, vec** 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 00000000000..91cc25a71c3 --- /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;