{
tree field, fields;
tree t;
- tree unqualified_variant = NULL_TREE;
if (type == error_mark_node)
return 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);
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);
= 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);
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;
}
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:
--- /dev/null
+// 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;
+}