[clang][Sema] Fix assertion in tryDiagnoseOverloadedCast (#108021)

Fixed an assertion failure in debug mode, and potential crashes in
release mode, when
diagnosing a failed cast caused indirectly by a failed implicit
conversion to the type of the constructor parameter.

For instance

```
template<typename>
struct StringTrait {};

template< int N >
struct StringTrait< const char[ N ] > {
  typedef char CharType;
  static const MissingIntT length = N - 1;
};

class String {
public:
  template <typename T>
  String(T& str, typename StringTrait<T>::CharType = 0);
};


class Exception {
public:
  Exception(String const&);
};

void foo() {
  throw Exception("some error");
}
```

`Exception(String const&)` is a matching constructor for `Exception`
from a `const char*`, via an implicit conversion to `String`. However,
the instantiation of the `String` constructor will fail because of the
missing type `MissingIntT` inside the specialization of `StringTrait`.

When trying to emit a diagnosis, `tryDiagnoseOverloadedCast` expects not
to have a matching constructor, but there is; it just could not be
instantiated.
This commit is contained in:
Alejandro Álvarez Ayllón 2024-09-18 10:11:03 +02:00 committed by GitHub
parent 94a98cf5dc
commit 0dd56858fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 34 additions and 1 deletions

View File

@ -397,6 +397,8 @@ Bug Fixes to C++ Support
- Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter
pack. #GH63819, #GH107560
- Fix a crash when a static assert declaration has an invalid close location. (#GH108687)
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -446,7 +446,12 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
: InitializationKind::CreateCast(/*type range?*/ range);
InitializationSequence sequence(S, entity, initKind, src);
assert(sequence.Failed() && "initialization succeeded on second try?");
// It could happen that a constructor failed to be used because
// it requires a temporary of a broken type. Still, it will be found when
// looking for a match.
if (!sequence.Failed())
return false;
switch (sequence.getFailureKind()) {
default: return false;

View File

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify %s
template<typename>
struct StringTrait {};
template< int N >
struct StringTrait< const char[ N ] > {
typedef char CharType;
static const MissingIntT length = N - 1; // expected-error {{unknown type name 'MissingIntT'}}
};
class String {
public:
template <typename T>
String(T& str, typename StringTrait<T>::CharType = 0);
};
class Exception {
public:
Exception(String const&);
};
void foo() {
throw Exception("some error"); // expected-error {{functional-style cast from 'const char[11]' to 'Exception' is not allowed}}
}