diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f636bac54134423e2a2713a7e4d3bf27ef051acc..03958da1fead083553e2f42a8591e5aca1b1526b 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -10317,7 +10317,8 @@ lookup_template_variable (tree templ, tree arglist) return build2 (TEMPLATE_ID_EXPR, NULL_TREE, templ, arglist); } -/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */ +/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR if it's + not dependent. */ tree finish_template_variable (tree var, tsubst_flags_t complain) @@ -10325,6 +10326,12 @@ finish_template_variable (tree var, tsubst_flags_t complain) tree templ = TREE_OPERAND (var, 0); tree arglist = TREE_OPERAND (var, 1); + /* If the template or arguments are dependent, then we + can't resolve the TEMPLATE_ID_EXPR yet. */ + if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) != 1 + || any_dependent_template_arguments_p (arglist)) + return var; + tree parms = DECL_TEMPLATE_PARMS (templ); arglist = coerce_template_parms (parms, arglist, templ, complain); if (arglist == error_mark_node) @@ -10352,19 +10359,14 @@ lookup_and_finish_template_variable (tree templ, tree targs, tsubst_flags_t complain) { tree var = lookup_template_variable (templ, targs); - if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (templ)) == 1 - && !any_dependent_template_arguments_p (targs)) - { - /* We may be called while doing a partial substitution, but the - type of the variable template may be auto, in which case we - will call do_auto_deduction in mark_used (which clears tf_partial) - and the auto must be properly reduced at that time for the - deduction to work. */ - complain &= ~tf_partial; - var = finish_template_variable (var, complain); - mark_used (var); - } - + /* We may be called while doing a partial substitution, but the + type of the variable template may be auto, in which case we + will call do_auto_deduction in mark_used (which clears tf_partial) + and the auto must be properly reduced at that time for the + deduction to work. */ + complain &= ~tf_partial; + var = finish_template_variable (var, complain); + mark_used (var); return convert_from_reference (var); } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 79b7cc72f212cef780a3eea65af2b883bb4ec3c8..db982d594e6d495cbdc93bcba8c2eba69882ec4e 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -4208,6 +4208,16 @@ finish_id_expression_1 (tree id_expression, } else { + if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + && variable_template_p (TREE_OPERAND (decl, 0)) + && !concept_check_p (decl)) + /* Try resolving this variable TEMPLATE_ID_EXPR (which is always + considered type-dependent) now, so that the dependence test that + follows gives us the right answer: if it represents a non-dependent + variable template-id then finish_template_variable will yield the + corresponding non-dependent VAR_DECL. */ + decl = finish_template_variable (decl); + bool dependent_p = type_dependent_expression_p (decl); /* If the declaration was explicitly qualified indicate @@ -4275,15 +4285,6 @@ finish_id_expression_1 (tree id_expression, /* Replace an evaluated use of the thread_local variable with a call to its wrapper. */ decl = wrap; - else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR - && !dependent_p - && variable_template_p (TREE_OPERAND (decl, 0)) - && !concept_check_p (decl)) - { - decl = finish_template_variable (decl); - mark_used (decl); - decl = convert_from_reference (decl); - } else if (concept_check_p (decl)) { /* Nothing more to do. All of the analysis for concept checks diff --git a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C index 86e46c96148dd9e9a4892d99d8bbf23a26b9cf44..caa4a056a2ed104818fbcc32557bf664646d76d3 100644 --- a/gcc/testsuite/g++.dg/cpp1y/noexcept1.C +++ b/gcc/testsuite/g++.dg/cpp1y/noexcept1.C @@ -5,9 +5,9 @@ template <int> bool b; template <typename> struct C { - template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression|different exception specifier" } + template <typename> friend int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" } }; -template <typename> int foo() noexcept(b<1>); +template <typename> int foo() noexcept(b<1>); // { dg-error "not usable in a constant expression" } auto a = C<int>(); diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ75.C b/gcc/testsuite/g++.dg/cpp1y/var-templ75.C new file mode 100644 index 0000000000000000000000000000000000000000..d2ab807ab9a53677725d50c438be57b916e784ed --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ75.C @@ -0,0 +1,20 @@ +// PR c++/108848 +// { dg-do compile { target c++14 } } + +template<class T> +struct tag_t { + template<class Sig> + static constexpr const Sig* var = nullptr; + + template<class Sig> + static const Sig* fun(); +}; + +template<class T> +constexpr tag_t<T> tag; + +template<class T> +void f() { + tag<int>.var<void>; // { dg-bogus "expected 'template' keyword" } + tag<int>.fun<void>(); // { dg-bogus "expected 'template' keyword" } +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ76.C b/gcc/testsuite/g++.dg/cpp1y/var-templ76.C new file mode 100644 index 0000000000000000000000000000000000000000..2acb815095378b94ad40babfa5480803a002a0cd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ76.C @@ -0,0 +1,13 @@ +// Verify we can evaluate a non-dependent variable template-id ahead of time. +// { dg-do compile { target c++14 } } + +template<int N> +constexpr int var = N; + +template<int N> void f(int) = delete; +template<int N> void f(...); + +template<class T> +void g() { + f<var<42>>(0); // { dg-error "deleted" } +}