diff options
author | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-17 17:00:38 +0000 |
---|---|---|
committer | jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-17 17:00:38 +0000 |
commit | 6b23c9879bef95a98acb0826d706ab974f47c840 (patch) | |
tree | af183c88efc573185903a522afb12f621645f17c | |
parent | 23de2c1dc774f7952c7d7e444471c40321871133 (diff) | |
download | gcc-6b23c9879bef95a98acb0826d706ab974f47c840.tar.gz |
PR c++/52282
* decl.c (build_ptrmemfunc_type): Don't build a different
RECORD_TYPE for a qualified PMF.
* cp-tree.h (TYPE_PTRMEMFUNC_FN_TYPE): Merge cv-quals.
(TYPE_PTRMEMFUNC_FN_TYPE_RAW): New.
* decl2.c (cplus_decl_attributes): Use TYPE_PTRMEMFUNC_FN_TYPE_RAW.
* tree.c (cp_walk_subtrees): Likewise.
(cp_build_qualified_type_real): Remove special PMF handling.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217660 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 25 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 2 | ||||
-rw-r--r-- | gcc/cp/tree.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/constexpr-decltype1.C | 99 |
6 files changed, 123 insertions, 54 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0c5e72b2027..42521c9b767 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2014-11-17 Jason Merrill <jason@redhat.com> + + PR c++/52282 + * decl.c (build_ptrmemfunc_type): Don't build a different + RECORD_TYPE for a qualified PMF. + * cp-tree.h (TYPE_PTRMEMFUNC_FN_TYPE): Merge cv-quals. + (TYPE_PTRMEMFUNC_FN_TYPE_RAW): New. + * decl2.c (cplus_decl_attributes): Use TYPE_PTRMEMFUNC_FN_TYPE_RAW. + * tree.c (cp_walk_subtrees): Likewise. + (cp_build_qualified_type_real): Remove special PMF handling. + 2014-11-15 Jason Merrill <jason@redhat.com> * parser.c (cp_parser_omp_declare_reduction_exprs): A block is not diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b69c7369589..54f7e9b8633 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3623,6 +3623,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true, before using this macro. */ #define TYPE_PTRMEMFUNC_FN_TYPE(NODE) \ + (cp_build_qualified_type (TREE_TYPE (TYPE_FIELDS (NODE)),\ + cp_type_quals (NODE))) + +/* As above, but can be used in places that want an lvalue at the expense + of not necessarily having the correct cv-qualifiers. */ +#define TYPE_PTRMEMFUNC_FN_TYPE_RAW(NODE) \ (TREE_TYPE (TYPE_FIELDS (NODE))) /* Returns `A' for a type like `int (A::*)(double)' */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1ef97637426..1f22c265b8c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8131,7 +8131,6 @@ build_ptrmemfunc_type (tree type) { tree field, fields; tree t; - tree unqualified_variant = NULL_TREE; if (type == error_mark_node) return type; @@ -8145,9 +8144,11 @@ build_ptrmemfunc_type (tree type) /* Make sure that we always have the unqualified pointer-to-member type first. */ - if (cp_type_quals (type) != TYPE_UNQUALIFIED) - unqualified_variant - = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type)); + if (cp_cv_quals quals = cp_type_quals (type)) + { + tree unqual = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type)); + return cp_build_qualified_type (unqual, quals); + } t = make_node (RECORD_TYPE); @@ -8168,22 +8169,6 @@ build_ptrmemfunc_type (tree type) information for this anonymous RECORD_TYPE. */ TYPE_NAME (t) = NULL_TREE; - /* If this is not the unqualified form of this pointer-to-member - type, set the TYPE_MAIN_VARIANT for this type to be the - unqualified type. Since they are actually RECORD_TYPEs that are - not variants of each other, we must do this manually. - As we just built a new type there is no need to do yet another copy. */ - if (cp_type_quals (type) != TYPE_UNQUALIFIED) - { - int type_quals = cp_type_quals (type); - TYPE_READONLY (t) = (type_quals & TYPE_QUAL_CONST) != 0; - TYPE_VOLATILE (t) = (type_quals & TYPE_QUAL_VOLATILE) != 0; - TYPE_RESTRICT (t) = (type_quals & TYPE_QUAL_RESTRICT) != 0; - TYPE_MAIN_VARIANT (t) = unqualified_variant; - TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (unqualified_variant); - TYPE_NEXT_VARIANT (unqualified_variant) = t; - } - /* Cache this pointer-to-member type so that we can find it again later. */ TYPE_SET_PTRMEMFUNC_TYPE (type, t); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 1b686ef95ae..fb8d0c82e40 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1474,7 +1474,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) { attributes = decl_attributes (decl, attributes, flags | ATTR_FLAG_FUNCTION_NEXT); - decl_attributes (&TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (*decl)), + decl_attributes (&TYPE_PTRMEMFUNC_FN_TYPE_RAW (TREE_TYPE (*decl)), attributes, flags); } else diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 21cecc2e39c..4502273fb57 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1082,18 +1082,6 @@ cp_build_qualified_type_real (tree type, = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type)); return t; } - else if (TYPE_PTRMEMFUNC_P (type)) - { - /* For a pointer-to-member type, we can't just return a - cv-qualified version of the RECORD_TYPE. If we do, we - haven't changed the field that contains the actual pointer to - a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong. */ - tree t; - - t = TYPE_PTRMEMFUNC_FN_TYPE (type); - t = cp_build_qualified_type_real (t, type_quals, complain); - return build_ptrmemfunc_type (t); - } else if (TREE_CODE (type) == TYPE_PACK_EXPANSION) { tree t = PACK_EXPANSION_PATTERN (type); @@ -1154,26 +1142,6 @@ cp_build_qualified_type_real (tree type, result = build_ref_qualified_type (result, type_memfn_rqual (type)); } - /* If this was a pointer-to-method type, and we just made a copy, - then we need to unshare the record that holds the cached - pointer-to-member-function type, because these will be distinct - between the unqualified and qualified types. */ - if (result != type - && TYPE_PTR_P (type) - && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE - && TYPE_LANG_SPECIFIC (result) == TYPE_LANG_SPECIFIC (type)) - TYPE_LANG_SPECIFIC (result) = NULL; - - /* We may also have ended up building a new copy of the canonical - type of a pointer-to-method type, which could have the same - sharing problem described above. */ - if (TYPE_CANONICAL (result) != TYPE_CANONICAL (type) - && TYPE_PTR_P (type) - && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE - && (TYPE_LANG_SPECIFIC (TYPE_CANONICAL (result)) - == TYPE_LANG_SPECIFIC (TYPE_CANONICAL (type)))) - TYPE_LANG_SPECIFIC (TYPE_CANONICAL (result)) = NULL; - return result; } @@ -3705,7 +3673,7 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (*tp)) - WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp)); + WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE_RAW (*tp)); break; case TYPE_ARGUMENT_PACK: diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-decltype1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-decltype1.C new file mode 100644 index 00000000000..1ff835036c8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-decltype1.C @@ -0,0 +1,99 @@ +// PR c++/52282 +// { dg-do run { target c++11 } } + +template <typename T, T V> +struct W { static constexpr T value() { return V; } }; + +template <typename T, T V> +struct X { typedef T type; static constexpr type value() { return V; } }; + +template <typename T, T V> +struct Y { using type = T; static constexpr type value() { return V; } }; + +template <typename T, T V> +struct Z { static constexpr decltype(V) value() { return V; } }; + +template <typename T, T V> +struct W_ { static constexpr T value = V; }; + +template <typename T, T V> +struct X_ { typedef T type; static constexpr type value = V; }; + +template <typename T, T V> +struct Y_ { using type = T; static constexpr type value = V; }; + +template <typename T, T V> +struct Z_ { static constexpr decltype(V) value = V; }; + + +static_assert(W<int, 10>::value() == 10, "oops"); +static_assert(X<int, 10>::value() == 10, "oops"); +static_assert(Y<int, 10>::value() == 10, "oops"); +static_assert(Z<int, 10>::value() == 10, "oops"); +static_assert(W_<int, 10>::value == 10, "oops"); +static_assert(X_<int, 10>::value == 10, "oops"); +static_assert(Y_<int, 10>::value == 10, "oops"); +static_assert(Z_<int, 10>::value == 10, "oops"); + +extern constexpr int a = 10; +static_assert(*W<const int*, &a>::value() == 10, "oops"); +static_assert(*X<const int*, &a>::value() == 10, "oops"); +static_assert(*Y<const int*, &a>::value() == 10, "oops"); +static_assert(*Z<const int*, &a>::value() == 10, "oops"); // ICE +static_assert(*W_<const int*, &a>::value == 10, "oops"); +static_assert(*X_<const int*, &a>::value == 10, "oops"); +static_assert(*Y_<const int*, &a>::value == 10, "oops"); +static_assert(*Z_<const int*, &a>::value == 10, "oops"); // ICE + +template <int V> constexpr int b() { return V; } +static_assert((W<int(*)(), &b<10>>::value())() == 10, "oops"); +static_assert((X<int(*)(), &b<10>>::value())() == 10, "oops"); // incorrect evaluation +static_assert((Y<int(*)(), &b<10>>::value())() == 10, "oops"); // incorrect evaluation +static_assert((Z<int(*)(), &b<10>>::value())() == 10, "oops"); // ICE +static_assert(W_<int(*)(), &b<10>>::value() == 10, "oops"); +static_assert(X_<int(*)(), &b<10>>::value() == 10, "oops"); +static_assert(Y_<int(*)(), &b<10>>::value() == 10, "oops"); +static_assert(Z_<int(*)(), &b<10>>::value() == 10, "oops"); // ICE + +constexpr struct C { + constexpr int c1() const { return 10; } + static constexpr int c2() { return 10; } +} c; + +static_assert((c.*W<int(C::*)()const, &C::c1>::value())() == 10, "oops"); +static_assert((c.*X<int(C::*)()const, &C::c1>::value())() == 10, "oops"); +static_assert((c.*Y<int(C::*)()const, &C::c1>::value())() == 10, "oops"); +static_assert((c.*Z<int(C::*)()const, &C::c1>::value())() == 10, "oops"); +static_assert((c.*W_<int(C::*)()const, &C::c1>::value)() == 10, "oops"); // incorrect evaluation +static_assert((c.*X_<int(C::*)()const, &C::c1>::value)() == 10, "oops"); // incorrect evaluation +static_assert((c.*Y_<int(C::*)()const, &C::c1>::value)() == 10, "oops"); // incorrect evaluation +static_assert((c.*Z_<int(C::*)()const, &C::c1>::value)() == 10, "oops"); // incorrect evaluation + +static_assert((W<int(*)(), &C::c2>::value())() == 10, "oops"); +static_assert((X<int(*)(), &C::c2>::value())() == 10, "oops"); // incorrect evaluation +static_assert((Y<int(*)(), &C::c2>::value())() == 10, "oops"); // incorrect evaluation +static_assert((Z<int(*)(), &C::c2>::value())() == 10, "oops"); // ICE +static_assert(W_<int(*)(), &C::c2>::value() == 10, "oops"); +static_assert(X_<int(*)(), &C::c2>::value() == 10, "oops"); +static_assert(Y_<int(*)(), &C::c2>::value() == 10, "oops"); +static_assert(Z_<int(*)(), &C::c2>::value() == 10, "oops"); // ICE + + +#include <assert.h> + +template <typename T, T V> +constexpr typename X_<T, V>::type X_<T, V>::value; + +int main() { + C c; + + // correctly evaluates inside method scope + int t1 = X<int(*)(), &b<10>>::value()(); + int t2 = (c.*X_<int(C::*)()const, &C::c1>::value)(); + int t3 = X<int(*)(), &C::c2>::value()(); + + assert(t1 == 10); + assert(t2 == 10); + assert(t3 == 10); + return 0; +} |