aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/c-cppbuiltin.c4
-rw-r--r--gcc/cp/mangle.c56
-rw-r--r--gcc/cp/pt.c24
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/nontype2.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/nontype3.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-subob1.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-subob2.C13
-rw-r--r--gcc/testsuite/g++.dg/template/nontype25.C6
-rw-r--r--gcc/testsuite/g++.dg/template/nontype8.C4
10 files changed, 126 insertions, 14 deletions
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 83f52fd..74ecca8 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -967,7 +967,8 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_enumerator_attributes=201411L");
cpp_define (pfile, "__cpp_nested_namespace_definitions=201411L");
cpp_define (pfile, "__cpp_fold_expressions=201603L");
- cpp_define (pfile, "__cpp_nontype_template_args=201411L");
+ if (cxx_dialect <= cxx17)
+ cpp_define (pfile, "__cpp_nontype_template_args=201411L");
cpp_define (pfile, "__cpp_range_based_for=201603L");
if (cxx_dialect <= cxx17)
cpp_define (pfile, "__cpp_constexpr=201603L");
@@ -998,6 +999,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_consteval=201811L");
cpp_define (pfile, "__cpp_constinit=201907L");
cpp_define (pfile, "__cpp_deduction_guides=201907L");
+ cpp_define (pfile, "__cpp_nontype_template_args=201911L");
cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806L");
cpp_define (pfile, "__cpp_impl_destroying_delete=201806L");
cpp_define (pfile, "__cpp_constexpr_dynamic_alloc=201907L");
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index ab2d8ec..43ff2e8 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2850,6 +2850,60 @@ write_member_name (tree member)
write_expression (member);
}
+/* EXPR is a base COMPONENT_REF; write the minimized base conversion path for
+ converting to BASE, or just the conversion of EXPR if BASE is null.
+
+ "Given a fully explicit base path P := C_n -> ... -> C_0, the minimized base
+ path Min(P) is defined as follows: let C_i be the last element for which the
+ conversion to C_0 is unambiguous; if that element is C_n, the minimized path
+ is C_n -> C_0; otherwise, the minimized path is Min(C_n -> ... -> C_i) ->
+ C_0."
+
+ We mangle the conversion to C_i if it's different from C_n. */
+
+static bool
+write_base_ref (tree expr, tree base = NULL_TREE)
+{
+ if (TREE_CODE (expr) != COMPONENT_REF)
+ return false;
+
+ tree field = TREE_OPERAND (expr, 1);
+
+ if (TREE_CODE (field) != FIELD_DECL || !DECL_FIELD_IS_BASE (field))
+ return false;
+
+ tree object = TREE_OPERAND (expr, 0);
+
+ tree binfo = NULL_TREE;
+ if (base)
+ {
+ tree cur = TREE_TYPE (object);
+ binfo = lookup_base (cur, base, ba_unique, NULL, tf_none);
+ }
+ else
+ /* We're at the end of the base conversion chain, so it can't be
+ ambiguous. */
+ base = TREE_TYPE (field);
+
+ if (binfo == error_mark_node)
+ {
+ /* cur->base is ambiguous, so make the conversion to
+ last explicit, expressed as a cast (last&)object. */
+ tree last = TREE_TYPE (expr);
+ write_string (OVL_OP_INFO (false, CAST_EXPR)->mangled_name);
+ write_type (build_reference_type (last));
+ write_expression (object);
+ }
+ else if (write_base_ref (object, base))
+ /* cur->base is unambiguous, but we had another base conversion
+ underneath and wrote it out. */;
+ else
+ /* No more base conversions, just write out the object. */
+ write_expression (object);
+
+ return true;
+}
+
/* <expression> ::= <unary operator-name> <expression>
::= <binary operator-name> <expression> <expression>
::= <expr-primary>
@@ -3268,6 +3322,8 @@ write_expression (tree expr)
ob = TREE_OPERAND (ob, 0);
write_expression (ob);
}
+ else if (write_base_ref (expr))
+ return;
else if (!is_dummy_object (ob))
{
write_string ("dt");
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 5f43e9c..cfe5dcd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6907,7 +6907,9 @@ template_parm_object_p (const_tree t)
}
/* Subroutine of convert_nontype_argument, to check whether EXPR, as an
- argument for TYPE, points to an unsuitable object. */
+ argument for TYPE, points to an unsuitable object.
+
+ Also adjust the type of the index in C++20 array subobject references. */
static bool
invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
@@ -6935,6 +6937,19 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
{
tree decl = TREE_OPERAND (expr, 0);
+ if (cxx_dialect >= cxx20)
+ while (TREE_CODE (decl) == COMPONENT_REF
+ || TREE_CODE (decl) == ARRAY_REF)
+ {
+ tree &op = TREE_OPERAND (decl, 1);
+ if (TREE_CODE (decl) == ARRAY_REF
+ && TREE_CODE (op) == INTEGER_CST)
+ /* Canonicalize array offsets to ptrdiff_t; how they were
+ written doesn't matter for subobject identity. */
+ op = fold_convert (ptrdiff_type_node, op);
+ decl = TREE_OPERAND (decl, 0);
+ }
+
if (!VAR_P (decl))
{
if (complain & tf_error)
@@ -6976,9 +6991,10 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
decl);
return true;
}
- else if (!same_type_ignoring_top_level_qualifiers_p
- (strip_array_types (TREE_TYPE (type)),
- strip_array_types (TREE_TYPE (decl))))
+ else if (cxx_dialect < cxx20
+ && !(same_type_ignoring_top_level_qualifiers_p
+ (strip_array_types (TREE_TYPE (type)),
+ strip_array_types (TREE_TYPE (decl)))))
{
if (complain & tf_error)
error ("the address of the %qT subobject of %qD is not a "
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype2.C b/gcc/testsuite/g++.dg/cpp1z/nontype2.C
index 75dc760..cf73166 100644
--- a/gcc/testsuite/g++.dg/cpp1z/nontype2.C
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype2.C
@@ -8,7 +8,7 @@ template<int* p> class X { };
template<const char *s> class Y {};
template<const std::type_info &> class Z {};
-X<&s.m> x7; // { dg-error "3:.& s.S::m. is not a valid template argument" }
+X<&s.m> x7; // { dg-error "3:.& s.S::m. is not a valid template argument" "" { target c++17_down } }
Y<"foo"> y1; // { dg-error "string literal" }
Z<typeid(p)> z1; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/nontype3.C b/gcc/testsuite/g++.dg/cpp1z/nontype3.C
index 80f1e98..1e02f1e 100644
--- a/gcc/testsuite/g++.dg/cpp1z/nontype3.C
+++ b/gcc/testsuite/g++.dg/cpp1z/nontype3.C
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++17_only } }
#ifndef __cpp_nontype_template_args
#error __cpp_nontype_template_args not defined
diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index 82fd602..7f1fe34 100644
--- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -334,8 +334,8 @@
#ifndef __cpp_nontype_template_args
# error "__cpp_nontype_template_args"
-#elif __cpp_nontype_template_args != 201411
-# error "__cpp_nontype_template_args != 201411"
+#elif __cpp_nontype_template_args != 201911
+# error "__cpp_nontype_template_args != 201911"
#endif
#ifndef __cpp_hex_float
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-subob1.C b/gcc/testsuite/g++.dg/cpp2a/nontype-subob1.C
new file mode 100644
index 0000000..4c1633e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-subob1.C
@@ -0,0 +1,25 @@
+// { dg-do compile { target c++20 } }
+
+template <auto N> struct A {};
+template <class,class> struct assert_same;
+template <class T> struct assert_same<T,T> {};
+
+#define TEQ(X,Y) static_assert(__is_same(A<(X)>,A<(Y)>))
+#define TNEQ(X,Y) static_assert(!__is_same(A<(X)>,A<(Y)>))
+
+struct C { int i; };
+
+struct B: C
+{
+ int j[3];
+} b;
+
+// { dg-final { scan-assembler _Z1f1AIXaddtL_Z1bE1iEE } }
+void f(A<&b.i>) {}
+TEQ(&b.i,&((C*)&b)->i);
+
+// { dg-final { scan-assembler _Z1g1AIXadixdtL_Z1bE1jLl1EEE } }
+void g(A<&b.j[0]+1>) {}
+TEQ(&b.j[1],&b.j[1]);
+TEQ(&b.j[1],&b.j[0]+1);
+TNEQ(&b.j[1],&b.j[0]);
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-subob2.C b/gcc/testsuite/g++.dg/cpp2a/nontype-subob2.C
new file mode 100644
index 0000000..a5768f6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-subob2.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -Wno-inaccessible-base }
+
+struct Base { int i; };
+template <int N> struct Derived : Derived<N-1>, Base {};
+template <> struct Derived<0> : Base {};
+
+template <int* P> struct A { };
+
+Derived<4> d;
+void f(A<&((Derived<0>&)d).i>) {}
+
+// { dg-final { scan-assembler _Z1f1AIXaddtcvR7DerivedILi0EEL_Z1dE1iEE } }
diff --git a/gcc/testsuite/g++.dg/template/nontype25.C b/gcc/testsuite/g++.dg/template/nontype25.C
index 3918bea4..aba8509 100644
--- a/gcc/testsuite/g++.dg/template/nontype25.C
+++ b/gcc/testsuite/g++.dg/template/nontype25.C
@@ -7,16 +7,16 @@ template<const A* a> class C {};
template<const B* b> class D {};
template<B* b> class E {};
-template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" }
+template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" "" { target { ! c++20 } } }
template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} // { dg-error "" "" { target { ! c++11 } } }
B b;
int main()
{
- C<static_cast<const A*>(&b)> c; // { dg-error "" }
+ C<static_cast<const A*>(&b)> c; // { dg-error "" "" { target c++17_down } }
D<&b> d;
E<const_cast<B*>(&b)> e; // { dg-error "" "" { target { ! c++11 } } }
- f(d, c); // { dg-error "" "" { target c++11 } }
+ f(d, c); // { dg-error "" "" { target { c++11 && { ! c++20 } } } }
g(d, e);
}
diff --git a/gcc/testsuite/g++.dg/template/nontype8.C b/gcc/testsuite/g++.dg/template/nontype8.C
index b4fbeae..a0458b9 100644
--- a/gcc/testsuite/g++.dg/template/nontype8.C
+++ b/gcc/testsuite/g++.dg/template/nontype8.C
@@ -6,9 +6,9 @@ template<int* p> class X { };
int a[10];
struct S { int m; static int s; } s;
-X<&a[2]> x3; // { dg-error "3:.& a\\\[2\\\]. is not a valid template argument" "" { target c++17 } }
+X<&a[2]> x3; // { dg-error "3:.& a\\\[2\\\]. is not a valid template argument" "" { target c++17_only } }
// { dg-error "" "" { target c++14_down } .-1 }
-X<&s.m> x4; // { dg-error "3:.& s.S::m. is not a valid template argument" "" { target c++17 } }
+X<&s.m> x4; // { dg-error "3:.& s.S::m. is not a valid template argument" "" { target c++17_only } }
// { dg-error "" "" { target c++14_down } .-1 }
X<&s.s> x5; // { dg-error "" "" { target { ! c++17 } } } &S::s must be used
X<&S::s> x6; // OK: address of static member