https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89512
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Slightly cleaned up testcase: struct A { template <typename T> static const int a = 0; }; struct B { template <typename T> static int foo () { return T::a; } }; int bar () { return B::foo<A> (); } Outside of a template this is caught by finish_id_expression_1 doing: /* If we didn't find anything, or what we found was a type, then this wasn't really an id-expression. */ if (TREE_CODE (decl) == TEMPLATE_DECL && !DECL_FUNCTION_TEMPLATE_P (decl)) { *error_msg = G_("missing template arguments"); return error_mark_node; } but in this case, we don't call finish_id_expression, but go through tsubst_qualified_id -> finish_qualified_id_expr So, I wonder if we shouldn't handle this in the latter, something like: --- gcc/cp/semantics.c.jj 2019-03-08 11:45:27.556465237 +0100 +++ gcc/cp/semantics.c 2019-03-13 17:24:46.260345284 +0100 @@ -2112,6 +2112,14 @@ finish_qualified_id_expr (tree qualifyin expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false, complain); } + else if (!template_p + && TREE_CODE (expr) == TEMPLATE_DECL + && !DECL_FUNCTION_TEMPLATE_P (expr)) + { + if (complain & tf_error) + error ("%qE missing template arguments", DECL_TEMPLATE_RESULT (expr)); + return error_mark_node; + } else { /* In a template, return a SCOPE_REF for most qualified-ids