llvm / llvm/llvm-project

Unexpected behavior when choosing the best sequence of implicit conversion

Open
#179,480 1 comment 0 reactions 0 assignees View on GitHub
clang:frontend
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

i have follow expample:
https://godbolt.org/z/vo1q4vdqd

class
```cpp
template
struct Variant {
Variant()=default;
Variant(const Variant&);
Variant(Variant&&);

template
Variant(T&&);
};
```
and class
```cpp
struct S1 {
public:
S1(const char*);

S1(const S1&);
S1(S1&&);

operator Variant() const;
};
```
when passing class `S1` to a function that accepts the `Variant` class, the choice of conversion sequence appears non-obvious and inconsistent.

with `VER 1` this results in `T constructor`, but with `VER 3` this results in `operator Variant`...

```cpp
#if VER == 1
S1 j = "";
take_by_ref(j);
take_by_rref(j);
take_by_value(j);
#endif
#if VER == 3
const S1 j = "";
take_by_ref(j);
take_by_rref(j);
take_by_value(j);
#endif
```
these options differ only in the `const` qualifier of the source object of the conversion sequence.
`S1::operator Variant() const` -- is the _const_-annotation member function and can be used by either const-object or non-const-object.

Why do these code variants choose different conversion paths depending only on the constancy of the source object of the conversion sequence?

https://eel.is/c++draft/over.match.best#general-2 is then closer to choosing in each of the variants the conversion sequence using `operator Variant()`:

> [(2.13)](https://eel.is/c++draft/over.match.best#general-2.13)
> F1 is generated from a non-template constructor and F2 is generated from a constructor template[.](https://eel.is/c++draft/over.match.best#general-2.sentence-1)

Replacing a Variant _template-constructor_ with a _non-template-constructors_ will produce ambiguous results.

other example with _consteval_ functions:
https://godbolt.org/z/Kh9KevezK

This case was born out of a discussion of the https://github.com/nlohmann/json/issues/5066

Contributor guide

Open the contributing guide

Research direction

No repository file or test is named. Start by reproducing the VER 1 and VER 3 Godbolt examples, then read the linked [over.match.best] standard wording and compare the constructor-template and conversion-operator candidates; done means establishing whether the differing conversion paths conform to the standard and identifying the appropriate LLVM component or resolution.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.