https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=d417b4f5414d9076300ab41974a14424f722688c https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=75b7b7fdc4597170f24c069ea13aa3e14f37fde7 https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=8e64d182850560dbedfabb88aac90d4fc6155067 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 304c01619da..3a15e6e2e47 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -166,6 +166,8 @@ static tree build_over_call (struct z_candidate *, int, tsubst_flags_t); /*c_cast_p=*/false, (COMPLAIN)) static tree convert_like_real (conversion *, tree, tree, int, bool, bool, tsubst_flags_t); +static tree convert_like_real_1 (conversion *, tree, tree, int, bool, + bool, tsubst_flags_t); static void op_error (const op_location_t &, enum tree_code, enum tree_code, tree, tree, tree, bool); static struct z_candidate *build_user_type_conversion_1 (tree, tree, int, @@ -6995,6 +6997,39 @@ maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum) " initializing argument %P of %qD", argnum, fn); } +/* Wrapper for convert_like_real_1 that handles creating IMPLICIT_CONV_EXPR. */ + +static tree +convert_like_real (conversion *convs, tree expr, tree fn, int argnum, + bool issue_conversion_warnings, + bool c_cast_p, tsubst_flags_t complain) +{ + /* Creating &TARGET_EXPR<> in a template breaks when substituting, + and creating a CALL_EXPR in a template breaks in finish_call_expr + so use an IMPLICIT_CONV_EXPR for this conversion. We would have + created such codes e.g. when calling a user-defined conversion + function. */ + tree conv_expr = NULL_TREE; + if (processing_template_decl + && convs->kind != ck_identity + && (CLASS_TYPE_P (convs->type) || CLASS_TYPE_P (TREE_TYPE (expr)))) + { + conv_expr = build1 (IMPLICIT_CONV_EXPR, convs->type, expr); + if (convs->kind != ck_ref_bind) + conv_expr = convert_from_reference (conv_expr); + if (!convs->bad_p) + return conv_expr; + /* Do the normal processing to give the bad_p errors. But we still + need to return the IMPLICIT_CONV_EXPR, unless we're returning + error_mark_node. */ + } + expr = convert_like_real_1 (convs, expr, fn, argnum, + issue_conversion_warnings, c_cast_p, complain); + if (expr == error_mark_node) + return error_mark_node; + return conv_expr ? conv_expr : expr; +} + /* Perform the conversions in CONVS on the expression EXPR. FN and ARGNUM are used for diagnostics. ARGNUM is zero based, -1 indicates the `this' argument of a method. INNER is nonzero when @@ -7006,9 +7041,9 @@ maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum) conversions to inaccessible bases are permitted. */ static tree -convert_like_real (conversion *convs, tree expr, tree fn, int argnum, - bool issue_conversion_warnings, - bool c_cast_p, tsubst_flags_t complain) +convert_like_real_1 (conversion *convs, tree expr, tree fn, int argnum, + bool issue_conversion_warnings, + bool c_cast_p, tsubst_flags_t complain) { tree totype = convs->type; diagnostic_t diag_kind; @@ -7466,6 +7501,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, expr = convert_bitfield_to_declared_type (expr); expr = fold_convert (type, expr); } + + /* Creating &TARGET_EXPR<> in a template would break when + tsubsting the expression, so use an IMPLICIT_CONV_EXPR + instead. This can happen even when there's no class + involved, e.g., when converting an integer to a reference + type. */ + if (processing_template_decl) + return build1 (IMPLICIT_CONV_EXPR, totype, expr); expr = build_target_expr_with_type (expr, type, complain); } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 782f0f6e60f..b7190fb8761 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9752,13 +9752,12 @@ compute_array_index_type_loc (location_t name_loc, tree name, tree size, NOP_EXPR with TREE_SIDE_EFFECTS; don't fold in that case. */; else { - size = instantiate_non_dependent_expr_sfinae (size, complain); size = build_converted_constant_expr (size_type_node, size, complain); /* Pedantically a constant expression is required here and so __builtin_is_constant_evaluated () should fold to true if it is successfully folded into a constant. */ - size = maybe_constant_value (size, NULL_TREE, - /*manifestly_const_eval=*/true); + size = fold_non_dependent_expr (size, complain, + /*manifestly_const_eval=*/true); if (!TREE_CONSTANT (size)) size = origsize; @@ -16784,10 +16783,8 @@ build_explicit_specifier (tree expr, tsubst_flags_t complain) /* Wait for instantiation, tsubst_function_decl will handle it. */ return expr; - expr = instantiate_non_dependent_expr_sfinae (expr, complain); - /* Don't let convert_like_real create more template codes. */ - processing_template_decl_sentinel s; expr = build_converted_constant_bool_expr (expr, complain); + expr = instantiate_non_dependent_expr_sfinae (expr, complain); expr = cxx_constant_value (expr); return expr; } diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 03a9c8e53c7..b113eacacb3 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1288,10 +1288,8 @@ build_noexcept_spec (tree expr, tsubst_flags_t complain) if (TREE_CODE (expr) != DEFERRED_NOEXCEPT && !value_dependent_expression_p (expr)) { - expr = instantiate_non_dependent_expr_sfinae (expr, complain); - /* Don't let convert_like_real create more template codes. */ - processing_template_decl_sentinel s; expr = build_converted_constant_bool_expr (expr, complain); + expr = instantiate_non_dependent_expr_sfinae (expr, complain); expr = cxx_constant_value (expr); } if (TREE_CODE (expr) == INTEGER_CST) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 612557bb717..710956e5a08 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6919,19 +6919,6 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type) || cxx_dialect >= cxx17) { - /* Calling build_converted_constant_expr might create a call to - a conversion function with a value-dependent argument, which - could invoke taking the address of a temporary representing - the result of the conversion. */ - if (COMPOUND_LITERAL_P (expr) - && CONSTRUCTOR_IS_DEPENDENT (expr) - && MAYBE_CLASS_TYPE_P (expr_type) - && TYPE_HAS_CONVERSION (expr_type)) - { - expr = build1 (IMPLICIT_CONV_EXPR, type, expr); - IMPLICIT_CONV_EXPR_NONTYPE_ARG (expr) = true; - return expr; - } /* C++17: A template-argument for a non-type template-parameter shall be a converted constant expression (8.20) of the type of the template-parameter. */ @@ -6940,6 +6927,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) /* Make sure we return NULL_TREE only if we have really issued an error, as described above. */ return (complain & tf_error) ? NULL_TREE : error_mark_node; + else if (TREE_CODE (expr) == IMPLICIT_CONV_EXPR) + { + IMPLICIT_CONV_EXPR_NONTYPE_ARG (expr) = true; + return expr; + } expr = maybe_constant_value (expr, NULL_TREE, /*manifestly_const_eval=*/true); expr = convert_from_reference (expr); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index aae5ff24c98..7c5a45c0848 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -926,7 +926,11 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only) return ok; } - init = maybe_constant_value (init); + /* Even non-dependent expressions can still have template + codes like CAST_EXPR, so use *_non_dependent_expr to cope. */ + init = fold_non_dependent_expr (init, complain); + if (init == error_mark_node) + return ok; /* If we were asked to only check constants, return early. */ if (const_only && !TREE_CONSTANT (init)) diff --git a/gcc/testsuite/g++.dg/conversion/op7.C b/gcc/testsuite/g++.dg/conversion/op7.C new file mode 100644 index 00000000000..c6401d109b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/op7.C @@ -0,0 +1,22 @@ +// PR c++/94190 - wrong no post-decrement operator error in template. + +struct S { operator long & (); } b; + +template void +foo () +{ + b--; + ++b; + --b; + b++; + !b; + ~b; + +b; + -b; +} + +void +bar () +{ + foo<0> (); +} diff --git a/gcc/testsuite/g++.dg/conversion/ref4.C b/gcc/testsuite/g++.dg/conversion/ref4.C new file mode 100644 index 00000000000..464a4cf6c0f --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref4.C @@ -0,0 +1,22 @@ +// PR c++/95789 +// { dg-do compile { target c++11 } } + +struct B { + int n; +}; + +template +struct A { + B& get() const { return f; } // { dg-error "binding reference" } + + B f; +}; + +int main() { + A a; + a.f = {}; + + a.get().n = 10; + if (a.f.n != 0) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/conversion/ref5.C b/gcc/testsuite/g++.dg/conversion/ref5.C new file mode 100644 index 00000000000..0042acd0670 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref5.C @@ -0,0 +1,14 @@ +// PR c++/96104 + +template void fn(T &); +class E {}; +struct F { + template void mfn(T t) { t, fn(E()); } // { dg-error "cannot bind non-const lvalue reference" } +}; +int +main() +{ + E e; + F f; + f.mfn(e); +} diff --git a/gcc/testsuite/g++.dg/conversion/ref6.C b/gcc/testsuite/g++.dg/conversion/ref6.C new file mode 100644 index 00000000000..fc87199053c --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/ref6.C @@ -0,0 +1,24 @@ +// PR c++/96179 +// { dg-do compile { target c++11 } } + +template struct vector +{ + void push_back(T) { } +}; + +struct dummy{ + int a; +}; + +void Modify_Dummy(dummy &d){ + d.a=1; +} + +template void Templated_Function(){ + vector A; + A.push_back(Modify_Dummy(dummy{0})); // { dg-error "cannot bind non-const lvalue reference" } +} + +int main(){ + Templated_Function(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl2.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl2.C new file mode 100644 index 00000000000..8a505769c3c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl2.C @@ -0,0 +1,21 @@ +// PR c++/92031 - bogus taking address of rvalue error. +// { dg-do compile { target c++11 } } + +struct x { const int& l; }; + +void a(const x&) {} + +template +void f() { + a(x { 0 }); +} + +void g() { + a(x { 0 }); +} + +void +test () +{ + f(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl3.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl3.C new file mode 100644 index 00000000000..e2021aa13e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl3.C @@ -0,0 +1,16 @@ +// PR c++/91465 - ICE with template codes in check_narrowing. +// { dg-do compile { target c++11 } } + +enum class D { X }; +enum class S { Z }; + +D foo(S) { return D{}; } +D foo(double) { return D{}; } + +template +struct Bar { + D baz(S s) + { + return D{foo(s)}; + } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl4.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl4.C new file mode 100644 index 00000000000..966a2e1ac9e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl4.C @@ -0,0 +1,33 @@ +// PR c++/93870 - wrong error when converting template non-type arg. +// { dg-do compile { target c++11 } } + +template struct EnumWrapper +{ + ENUM value; + + constexpr operator ENUM() const + { + return value; + } +}; + +enum E : int { V }; + +constexpr EnumWrapper operator ~(E a) +{ + return {E(~int(a))}; +} + +template struct R +{ + static void Func(); +}; + +template struct S : R<~X> +{ +}; + +void Test() +{ + S::Func(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl5.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl5.C new file mode 100644 index 00000000000..c83e6d83ed9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl5.C @@ -0,0 +1,13 @@ +// PR c++/94068 - ICE with template codes in check_narrowing. +// { dg-do compile { target c++11 } } + +enum class A { A1, A2 }; +A foo (); +long foo (int); + +template +void +bar () +{ + const auto c{foo ()}; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/conv-tmpl6.C b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl6.C new file mode 100644 index 00000000000..2df3a6cc129 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/conv-tmpl6.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++11 } } + +struct A +{ + constexpr A(int) { } + constexpr operator int() const { return 1; }; +}; + +template +struct B +{ + static constexpr A a = A(N); + int ar[a]; +}; + +B b; diff --git a/gcc/testsuite/g++.dg/cpp1z/conv-tmpl1.C b/gcc/testsuite/g++.dg/cpp1z/conv-tmpl1.C new file mode 100644 index 00000000000..5b1205349d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/conv-tmpl1.C @@ -0,0 +1,10 @@ +// PR c++/91465 - ICE with template codes in check_narrowing. +// { dg-do compile { target c++17 } } + +enum class E { Z }; + +template +void foo(F) +{ + E{char(0)}; +}