Bug 89062 - class template argument deduction failure with parentheses
Summary: class template argument deduction failure with parentheses
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 12.0
Assignee: Patrick Palka
Keywords: rejects-valid
: 100979 101509 (view as bug list)
Depends on:
Reported: 2019-01-25 18:25 UTC by Barry Revzin
Modified: 2021-10-06 15:18 UTC (History)
8 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2019-01-25 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Barry Revzin 2019-01-25 18:25:56 UTC
Reduced from StackOverflow https://stackoverflow.com/q/54369677/2069064:

template<class T>
struct Foo {
    Foo(T) {}

template<class T>
struct Bar {
     Bar(T) {};

Foo foo(Bar{1});

This fails with:

<source>:11:9: error: 'auto' parameter not permitted in this context
 Foo foo(Bar{1});
Compiler returned: 1

Every other alternative is fine:

Foo foo(Bar(1)); // ok
Foo foo{Bar{1}}; // ok
Foo foo{Bar(1)}; // ok
Foo foo(Bar<int>(1)); // ok
Foo foo(Bar<int>{1}); // ok
Foo<Bar<int>> foo(Bar{1}); // ok
Comment 1 Marek Polacek 2019-01-25 18:30:27 UTC
Comment 2 Barry Revzin 2019-01-25 18:32:36 UTC
This may or may not be the same bug as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87709, I do not know.
Comment 3 ensadc 2019-01-25 19:40:54 UTC
I think this should be treated as a different bug from bug 87709. In bug 87709, the error is emitted in cp_parser_type_id_1. In this bug, the error is produced by grokdeclarator.
Comment 4 S. Davis Herring 2019-12-19 21:13:16 UTC
You don't need two different class templates; just

  Foo foo(Foo{1});

fails identically.
Comment 5 Nikita Lisitsa 2020-10-01 07:08:52 UTC
Any updates on this? Can confirm this on all gcc versions from 7.1 to 10.2 (see https://godbolt.org/z/4qnfea). Interestingly, for a variadic-template constructor only the first argument triggers the error, i.e.

template <typename T>
struct A
    A(T) {}

template <typename T>
A(T) -> A<T>;

template <typename T>
struct B

    template <typename ... Args>
    B(Args const & ...){}


void test()
    B<int> b1(A{0}, A{0}, A{0}); // error
    B<int> b2(A<int>{0}, A{0}, A{0}); // ok
Comment 6 Marek Polacek 2020-10-01 13:35:49 UTC
Unfortunately, not yet.  I've taken a look at this, and I think I know what the problem is, but haven't written a fix yet.
Comment 7 Marek Polacek 2021-06-09 00:46:37 UTC
*** Bug 100979 has been marked as a duplicate of this bug. ***
Comment 8 Marek Polacek 2021-07-19 12:49:38 UTC
*** Bug 101509 has been marked as a duplicate of this bug. ***
Comment 9 GCC Commits 2021-08-11 19:59:54 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:


commit r12-2859-g6186708312780bb2139da01946abdde39667e985
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Aug 11 15:58:30 2021 -0400

    c++: most vexing parse and braced CTAD [PR89062]
    Here grokdeclarator is emitting the error
      error: class template placeholder âFooâ not permitted in this context
    during the tentative (and ultimately futile) parse of 'x' as a function
    declaration.  This happens because when parsing 'Foo{1}',
    cp_parser_parameter_declaration yields a parameter declaration with no
    declarator and whose type is a CTAD placeholder, and stops short of
    consuming the '{'.  The caller cp_parser_parameter_declaration_list then
    calls grokdeclarator on this declarator, hence the error, and soon
    thereafter we abort this tentative parse since the next token '{'
    doesn't make sense in the context of a parameter list.
    Note that we don't have this issue with parenthesized CTAD
      Foo<int> x(Foo(1));
    because in this case cp_parser_direct_declarator (called indirectly from
    c_p_p_d) consumes the '(' and returns cp_error_declarator instead of a
    NULL declarator (and also simulates a parse error), and grokdeclarator
    exits early for this declarator without emitting any error.
    Since grokdeclarator doesn't take a 'complain' parameter, to fix this we
    need to avoid calling grokdeclarator in this situation.  To that end
    this patch makes c_p_p_d simulate an error when a construct is a CTAD
    expression and definitely not a parameter declaration, so that c_p_p_d_l
    can avoid calling grokdeclarator by checking for this simulated error.
    Alternatively we could keep all this logic inside c_p_p_d_l and not
    touch c_p_p_d at all, but this approach seems slightly less adhoc.
            PR c++/89062
            * parser.c (cp_parser_parameter_declaration_list): Don't call
            grokdeclarator if cp_parser_error_occurred.
            (cp_parser_parameter_declaration): Simulate an error if we see
            the beginning of a CTAD form, i.e. if we see an opening brace
            after the decl-specifier-seq and the type is a CTAD placeholder.
            * g++.dg/cpp1z/class-deduction97.C: New test.
Comment 10 Patrick Palka 2021-08-11 20:03:47 UTC
Fixed for GCC 12.
Comment 11 Avi Kivity 2021-10-06 15:18:30 UTC
Seeing this in 11.2, so asking for a backport.