diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -267,17 +267,17 @@ `GH55216 `_. - Correctly set expression evaluation context as 'immediate function context' in consteval functions. - This fixes `GH51182 `_. - + This fixes `GH51182 ` - Fixes an assert crash caused by looking up missing vtable information on ``consteval`` virtual functions. Fixes `GH55065 `_. - - Skip rebuilding lambda expressions in arguments of immediate invocations. This fixes `GH56183 `_, `GH51695 `_, `GH50455 `_, `GH54872 `_, `GH54587 `_. +- Fixed a crash during template instantiation on a conversion operator during constraint + evaulation. Fixes `GH50891 `_. C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4020,6 +4020,9 @@ // // Note: SecondStepOfCopyInit is only ever true in this case when // evaluating whether to produce a C++98 compatibility warning. + // + // The last check avoids an infinite template expansion loop in + // requirements checking by skipping the conversion functions check. if (S.getLangOpts().CPlusPlus17 && Args.size() == 1 && !SecondStepOfCopyInit) { Expr *Initializer = Args[0]; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -7565,6 +7565,24 @@ return; } + // We won't go through a user-defined type conversion function to convert a + // derived to base as such conversions are given Conversion Rank. They only + // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] + // Peforming this check here avoids possible infinite template expansion + // in the following call to DeduceTemplateArguments(). + QualType FromCanon = + Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); + if (FromCanon == ToCanon || + IsDerivedFrom(CandidateSet.getLocation(), FromCanon, ToCanon)) { + OverloadCandidate &Candidate = CandidateSet.addCandidate(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_trivial_conversion; + return; + } + TemplateDeductionInfo Info(CandidateSet.getLocation()); CXXConversionDecl *Specialization = nullptr; if (TemplateDeductionResult Result diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -262,3 +262,18 @@ template struct S {}; void f(C auto); } // namespace GH55567 + +namespace Issue50891 { +template +concept Numeric = + requires(T a) { + foo(a); + }; + +struct Deferred { + friend void foo(Deferred); + template operator TO(); +}; + +static_assert(Numeric); // should not crash clang +} // namespace Issue50891