llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.93k stars 11.94k forks source link

[Clang] Issue with additional default arguments in function redeclaration #60521

Open elizabethandrews opened 1 year ago

elizabethandrews commented 1 year ago

Clang ignores function redeclaration which provides additional default arguments and throws diagnostic "error: no matching function for call" - https://godbolt.org/z/bnha5jEGG

The test passes if namespace M is defined after the function redeclaration - https://godbolt.org/z/c1qhWf7MP

Both cases should work.

Relevant C++ standard -

“When a declaration of a function is introduced by way of a using-declaration (7.3.3), any default argument information associated with the declaration is made known as well. If the function is redeclared thereafter in the namespace with additional default arguments, the additional arguments are also known at any point following the redeclaration where the using-declaration is in scope.”

llvmbot commented 1 year ago

@llvm/issue-subscribers-clang-frontend

shafik commented 1 year ago

The language in dcl.fct.default p9 has changed significantly, it was changed by the P1787 which contained a major set of changes to how we find names. It looks like this was possible part of DR 1907.

The new language says:

When an overload set contains a declaration of a function that inhabits a scope S, any default argument associated with any reachable declaration that inhabits S is available to the call. [Note 7: The candidate might have been found through a using-declarator from which the declaration that provides the default argument is not reachable. — end note]

Which I read a possibly agreeing with clang here but I am not totally sure if that was the intent, DR1907 muddies the waters quite a bit here.

CC @hubert-reinterpretcast please let me know what you think.

hubert-reinterpretcast commented 1 year ago

DR1907 muddies the waters quite a bit here.

The wording resolving DR 1907 was fairly straightforward (see N4928 [temp.res.general] paragraph 2).

hubert-reinterpretcast commented 1 year ago

CC @hubert-reinterpretcast please let me know what you think.

namespace N {
int f(int i, int j = 0) { return i + j + 10; }
}

namespace M {
using N::f;
}

namespace N {
int f(int i = 0, int j);
}

void foo() {

    int a = N::f(); // Works

    using M::f;
    int b = f(); // Does not work
}

The using-declarator names the first declaration with a default argument, which inhabits the namespace scope of N. That named declaration is in the overload set. At the point of the call, the second declaration with a default argument is reachable and also inhabits the namespace scope of N. The case can be simplified by "physically" using M::f in the call.

hubert-reinterpretcast commented 1 year ago

[Note 7: The candidate might have been found through a using-declarator from which the declaration that provides the default argument is not reachable. — end note]

I believe that the note is trying to highlight a case where the wording matters: later default arguments are available to the call despite being found through a using-declarator that did not "see" said default arguments (otherwise, the overload set include the later declarations as well).

See also core/2020/11/10210.

shafik commented 1 year ago

DR1907 muddies the waters quite a bit here.

The wording resolving DR 1907 was fairly straightforward (see N4928 [temp.res.general] paragraph 2).

Yeah, I think I was previously confused which case "determined that the case should be ill-formed" referred to, but after rereading it it is referring to the first code example and not the second.

shafik commented 1 year ago

So it looks like clang is wrong here.