Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[conv.qual] identity conversion and similar type #4851

Open
xmh0511 opened this issue Sep 1, 2021 · 1 comment · May be fixed by #4860
Open

[conv.qual] identity conversion and similar type #4851

xmh0511 opened this issue Sep 1, 2021 · 1 comment · May be fixed by #4860
Assignees

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Sep 1, 2021

In [dcl.init.ref] p4, the "reference-related" is defined as

Given types “cv1 T1” and “cv2 T2”, “cv1 T1” is reference-related to “cv2 T2” if T1 is similar ([conv.qual]) to T2, or T1 is a base class of T2.

Consider this example

int a;
int&& rf = a;  // ill-formed

Presumably, it is restricted by [dcl.init.ref#5.4.4]

If T1 is reference-related to T2:

  • [...]
  • if the reference is an rvalue reference, the initializer expression shall not be an lvalue.

Is the type int similar to int? It should be determined by [conv.qual] p2

Two types T1 and T2 are similar if they have qualification-decompositions with the same n such that corresponding Pi components are either the same or one is “array of Ni" and the other is “array of unknown bound of”, and the types denoted by U are the same.

However, the qualification-decomposition of type int does not have any Pi component. Maybe, one could argue since they are empty, they're the same.


From a prvalue of type int to type int, or from a prvalue of type int to int const volatile, Is it a qualified conversion? It seems [conv.qual] p3 can apply to these two conversions except that whether [conv.qual#3.2] is suitable for empty Pi, however, we can also say it's [conv.integral]

A prvalue of an integer type can be converted to a prvalue of another integer type.

Types bool, char, wchar_­t, char8_­t, char16_­t, char32_­t, and the signed and unsigned integer types, and cv-qualified versions ([basic.type.qualifier]) thereof, are collectively termed integral types. A synonym for integral type is integer type.

Maybe, we should give this conversion accurate meaning.


For class type, it is a bit different, since a prvalue of cv class type can retain the cv-qualification. So, assume T is a class type, from a prvalue of type volatile const T to type T is a user-defined conversion? Why I say it is a user-defined conversion because of [over.best.ics#general-6] and [over.ics.user]

When the parameter has a class type and the argument expression has the same type, the implicit conversion sequence is an identity conversion. When the parameter has a class type and the argument expression has a derived class type, the implicit conversion sequence is a derived-to-base conversion from the derived class to the base class.

A conversion of an expression of class type to the same class type is given Exact Match rank, and a conversion of an expression of class type to a base class of that type is given Conversion rank, in spite of the fact that a constructor (i.e., a user-defined conversion function) is called for those cases.

Since T and volatile const T are not the same type, hence the conversion is user-defined conversion?

struct Base{
    Base() = default;
    Base(Base const volatile&){}
};
struct A:Base{
    A() = default;
    A(A const volatile&){}
};
struct B{B(A const volatile&){}};
void fun(A){std::cout<<"#1\n";}
void fun(Base){std::cout<<"#2\n";}
void fun(B){std::cout<<"#3\n";}
void fun2(Base){std::cout<<"#4\n";}
void fun2(B){std::cout<<"#5\n";}
int main() {
   A volatile const a;
   fun(a);
   fun2(a);
}

Obviously, #1 and #4 are called. Maybe we should fix [over.best.ics#general-6] and [over.ics.user] to that

When the parameter has a class type and the cv-unqualified version of argument expression's type has the same type, the implicit conversion sequence is an identity conversion. When the parameter has a class type and the argument expression has a (possible cv-qualified) derived class type, the implicit conversion sequence is a derived-to-base conversion from the derived class to the base class.

A conversion of an expression of "cv1 T1" to "cv2 T2" is given Exact Match rank if "T1" and “T2” are the same class type, and a conversion of an expression of "cv1 T1" to "cv2 T2" is given Conversion rank if T2 is a base class of T1 and "cv2 T2" is reference-compatible with "cv1 T1" , in spite of the fact that a constructor (i.e., a user-defined conversion function) is called for those cases.

These issues arise from the permitted types.

@jensmaurer
Copy link
Member

First of all, [conv.qual] p1 clearly says that a qualification-decomposition with n=0 for a type T does exist, and simply is cv U. No P exists for that case, so the "if" in p3.2 is vacuously false: "if P is array of unknown bound" is false because there is no P, so it can't possibly be "array of unknown bound".

A conversion from int to const volatile int should be a qualification conversion. It is under [conv.qual], but as you noticed, it is also an integral conversion, which is wrong and needs to be fixed.

For class types, we should simply use "similar" instead of "same" class type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants