[cfe-dev] Standard conversion sequences and PerformImplicitConversion
Bevin Hansson via cfe-dev
cfe-dev at lists.llvm.org
Mon Dec 9 02:01:18 PST 2019
While looking at generalizing address space support in Clang, I've
struck upon some oddities with the emission of standard conversion
sequences in PerformImplicitConversion. The method claims to lower every
step of the conversions contained in an SCS that are passed to it.
However, in reality the method completely ignores the intermediate types
of the individual conversions, resulting in certain conversion steps
doing more than they should be. For example, if an SCS consists of a
pointer conversion followed by a qualification conversion, the pointer
conversion will actually perform both steps, and the qualification
conversion will simply be a no-op.
The reason for this behavior is because PerformImplicitConversion never
looks at the intermediate destination types of the conversions, only at
the final type. This means that the code for, say, pointer conversion
must be able to handle both pointer conversion and qualification
conversion at the same time, even though they should be done in separate
The reason I'm stumbling onto this is because there is (what seems to
be?) a hack in IsQualificationConversion that prevents Clang from
considering certain address space conversions as qualification
conversions, even though they should be. Removing that causes Clang to
create an ICS for "(__private void *)generic_char_ptr" of the form:
* Pointer conversion: "char *" -> "void *"
* Qualification conversion: "void *" -> "__private void *"
This sequence is correct. However, PerformImplicitConversion tries to
have the pointer conversion handle the entire ICS, and this does not
work as CheckPointerConversion cannot handle address space conversions.
Adding the ability to emit address space conversions to it solves the
problem, but it does not solve the case where the pointer conversion is
a derived-to-base conversion instead, and that is less easy to solve.
Modifying PerformImplicitConversion to obey/verify the intermediate
conversion types causes test failures, due to a bunch of different reasons:
* Many conversions of functions/function pointers omit the exception
specifications in SCSes in interesting ways
* Some code (such as direct reference binding initialization) builds
'identity' and derived-to-base SCSes with incorrect intermediate types
* Some manually built SCSes haven't actually set the intermediate types
There are probably a few more I've missed here.
Is it supposed to be this way? It feels like the method is taking
shortcuts with the conversions and that the rest of the codebase has
simply coded around this behavior.
For reference, the review with a comment about this is here:
More information about the cfe-dev