diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/c-family/c-cppbuiltin.c | 4 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 56 | ||||
-rw-r--r-- | gcc/cp/pt.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/nontype2.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/nontype3.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-subob1.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/nontype-subob2.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/nontype25.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/nontype8.C | 4 |
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 |