The crux of the problem in this PR is that type_dependent_expression_p returns true for a FUNCTION_DECL that is not actually type-dependent. This leads tsubst_decl to attempt to perform template argument substitution on the template arguments of the FUNCTION_DECL, which do not necessarily correspond with the current template arguments.
In the test case provided in the PR, the FUNCTION_DECL in question (which is used in a CALL_EXPR built by build_min_non_dep_op_overload during processing of the template function f()) is the following: <function_decl 0x7ffff6a0d700 operator| type <function_type 0x7ffff6a0c738 type <template_type_parm 0x7ffff6a0c690 auto type_0 type_6 VOID align 8 symtab 0 alias set -1 canonical type 0x7ffff6a0c690 index 0 level 1 orig_level 2 chain <type_decl 0x7ffff69f1e40 auto>> QI size <integer_cst 0x7ffff6898f48 constant 8> unit size <integer_cst 0x7ffff6898f60 constant 1> align 8 symtab 0 alias set -1 canonical type 0x7ffff6a0c738 arg-types <tree_list 0x7ffff6a09898 value <record_type 0x7ffff69f0b28 Option> chain <tree_list 0x7ffff6a09820 value <record_type 0x7ffff6a08888 Option> chain <tree_list 0x7ffff68acc80 value <void_type 0x7ffff68be150 void>>>> pointer_to_this <pointer_type 0x7ffff6a0c7e0>> addressable public external QI file /home/patrick/code/gcc/gcc/testsuite/g++.dg/template/pr69091.C line 8 col 6 align 8 context <translation_unit_decl 0x7ffff68a4168 D.1> full-name "auto operator|(Option<ValueType, Value>, OptionsRhs) [with ValueType = canine_t; ValueType Value = (canine_t)0u; OptionsRhs = Option<canine_t, (canine_t)1u>]" template-info 0x7ffff69ffcc0> type_dependent_expression_p returns true for this FUNCTION_DECL because its TREE_TYPE is 'auto'. Direct calls to operator| do not have this problem because in such a case the CALL_EXPR_FN of the CALL_EXPR that's built is an OVERLOAD (to a TEMPLATE_DECL), which tsubst does not touch. This patch makes it so that type_dependent_expression_p considers a FUNCTION_DECL with template info to be type-dependent if and only if any of its template arguments are dependent, similar to how C++14 variable templates are handled. Thus for the above FUNCTION_DECL we would return false because all of its template arguments are non-dependent: <tree_vec 0x7ffff6897c00 length 3 elt 0 <enumeral_type 0x7ffff69f09d8 canine_t ...> elt 1 <integer_cst 0x7ffff69fdee8 type <enumeral_type 0x7ffff69f09d8 canine_t> constant 0> elt 2 <record_type 0x7ffff6a08888 Option type_5 type_6 QI ...>> Bootstrapped and regtested on x86_64-pc-linux-gnu with no new regressions, and also tested against Boost. Is this change OK? gcc/cp/ChangeLog: PR c++/69091 * pt.c (type_dependent_expression_p): For a function template specialization, a type is dependent iff any of its template arguments are. gcc/testsuite/ChangeLog: PR c++/69091 * g++.dg/template/pr69091.C: New test. --- gcc/cp/pt.c | 8 ++++---- gcc/testsuite/g++.dg/template/pr69091.C | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/pr69091.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index edec774..403c5ac 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -22759,12 +22759,12 @@ type_dependent_expression_p (tree expression) || dependent_scope_p (scope)); } + /* A function template specialization is type-dependent if it has any + dependent template arguments. */ if (TREE_CODE (expression) == FUNCTION_DECL && DECL_LANG_SPECIFIC (expression) - && DECL_TEMPLATE_INFO (expression) - && (any_dependent_template_arguments_p - (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression))))) - return true; + && DECL_TEMPLATE_INFO (expression)) + return any_dependent_template_arguments_p (DECL_TI_ARGS (expression)); if (TREE_CODE (expression) == TEMPLATE_DECL && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression)) diff --git a/gcc/testsuite/g++.dg/template/pr69091.C b/gcc/testsuite/g++.dg/template/pr69091.C new file mode 100644 index 0000000..ec7bb25 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/pr69091.C @@ -0,0 +1,25 @@ +// PR c++/69091 +// { dg-do compile { target c++14 } } + +template <class ValueType, ValueType> +struct Option {}; + +template <class ValueType, ValueType Value, class OptionsRhs> +auto operator|(Option<ValueType, Value>, OptionsRhs) { + return Value; +} + +enum canine_t { no, yes }; +Option<canine_t, no> cat; +Option<canine_t, yes> dog; + +template <class T> +void f(T) { + cat | dog; +} + +struct A {}; +int main() { + f(A{}); + return 0; +} -- 2.7.0.83.gdfccd77.dirty