diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5fe86f8bdecd5..a5e72fc917f38 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -212,11 +212,6 @@ Improvements to Clang's diagnostics of FAM-like arrays. - Clang now correctly diagnoses a warning when defercencing a void pointer in C mode. This fixes `Issue 53631 `_ -- Clang will now diagnose an overload set where a candidate has a constraint that - refers to an expression with a previous error as nothing viable, so that it - doesn't generate strange cascading errors, particularly in cases where a - subsuming constraint fails, which would result in a less-specific overload to - be selected. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index ae2f37dc4b321..25e00860060f0 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -44,7 +44,6 @@ class ConstraintSatisfaction : public llvm::FoldingSetNode { using Detail = llvm::PointerUnion; bool IsSatisfied = false; - bool ContainsErrors = false; /// \brief Pairs of unsatisfied atomic constraint expressions along with the /// substituted constraint expr, if the template arguments could be @@ -79,7 +78,6 @@ struct ASTConstraintSatisfaction final : UnsatisfiedConstraintRecord> { std::size_t NumRecords; bool IsSatisfied : 1; - bool ContainsErrors : 1; const UnsatisfiedConstraintRecord *begin() const { return getTrailingObjects(); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 93c598b2eba48..834b60a2744d6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2845,8 +2845,6 @@ def err_template_arg_list_constraints_not_satisfied : Error< "template template parameter|template}0 %1%2">; def note_substituted_constraint_expr_is_ill_formed : Note< "because substituted constraint expression is ill-formed%0">; -def note_constraint_references_error - : Note<"constraint depends on a previously diagnosed expression">; def note_atomic_constraint_evaluated_to_false : Note< "%select{and|because}0 '%1' evaluated to false">; def note_concept_specialization_constraint_evaluated_to_false : Note< diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 6aaa6a481cf84..fb4812675d9a3 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -928,8 +928,6 @@ class Sema; return ExplicitCallArguments; } - bool NotValidBecauseConstraintExprHasError() const; - private: friend class OverloadCandidateSet; OverloadCandidate() diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index 67911f7e82157..18582782888c3 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -19,11 +19,10 @@ #include "llvm/ADT/FoldingSet.h" using namespace clang; -ASTConstraintSatisfaction::ASTConstraintSatisfaction( - const ASTContext &C, const ConstraintSatisfaction &Satisfaction) - : NumRecords{Satisfaction.Details.size()}, - IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{ - Satisfaction.ContainsErrors} { +ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, + const ConstraintSatisfaction &Satisfaction): + NumRecords{Satisfaction.Details.size()}, + IsSatisfied{Satisfaction.IsSatisfied} { for (unsigned I = 0; I < NumRecords; ++I) { auto &Detail = Satisfaction.Details[I]; if (Detail.second.is()) @@ -47,6 +46,7 @@ ASTConstraintSatisfaction::ASTConstraintSatisfaction( } } + ASTConstraintSatisfaction * ASTConstraintSatisfaction::Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction) { diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 334897b32403f..1f573346b4410 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -853,10 +853,7 @@ ExprDependence clang::computeDependence(ConceptSpecializationExpr *E, ExprDependence D = ValueDependent ? ExprDependence::Value : ExprDependence::None; - auto Res = D | toExprDependence(TA); - if(!ValueDependent && E->getSatisfaction().ContainsErrors) - Res |= ExprDependence::Error; - return Res; + return D | toExprDependence(TA); } ExprDependence clang::computeDependence(ObjCArrayLiteral *E) { diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 7426b553fcfb8..614c9b8b05aa3 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -206,30 +206,6 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // Evaluator has decided satisfaction without yielding an expression. return ExprEmpty(); - // We don't have the ability to evaluate this, since it contains a - // RecoveryExpr, so we want to fail overload resolution. Otherwise, - // we'd potentially pick up a different overload, and cause confusing - // diagnostics. SO, add a failure detail that will cause us to make this - // overload set not viable. - if (SubstitutedAtomicExpr.get()->containsErrors()) { - Satisfaction.IsSatisfied = false; - Satisfaction.ContainsErrors = true; - - PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error); - SmallString<128> DiagString; - DiagString = ": "; - Msg.EmitToString(S.getDiagnostics(), DiagString); - unsigned MessageSize = DiagString.size(); - char *Mem = new (S.Context) char[MessageSize]; - memcpy(Mem, DiagString.c_str(), MessageSize); - Satisfaction.Details.emplace_back( - ConstraintExpr, - new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{ - SubstitutedAtomicExpr.get()->getBeginLoc(), - StringRef(Mem, MessageSize)}); - return SubstitutedAtomicExpr; - } - EnterExpressionEvaluationContext ConstantEvaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); SmallVector EvaluationDiags; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 02a05b2b7bcf0..32ece5cc47918 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10119,12 +10119,6 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( } } -bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { - return DeductionFailure.Result == Sema::TDK_ConstraintsNotSatisfied && - static_cast(DeductionFailure.Data) - ->Satisfaction.ContainsErrors; -} - /// Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// @@ -10177,18 +10171,10 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, Best = end(); for (auto *Cand : Candidates) { Cand->Best = false; - if (Cand->Viable) { + if (Cand->Viable) if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind)) Best = Cand; - } else if (Cand->NotValidBecauseConstraintExprHasError()) { - // This candidate has constraint that we were unable to evaluate because - // it referenced an expression that contained an error. Rather than fall - // back onto a potentially unintended candidate (made worse by by - // subsuming constraints), treat this as 'no viable candidate'. - Best = end(); - return OR_No_Viable_Function; - } } // If we didn't find any viable functions, abort. diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 3f5a85786da4c..f41b247c306f5 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -772,7 +772,6 @@ static ConstraintSatisfaction readConstraintSatisfaction(ASTRecordReader &Record) { ConstraintSatisfaction Satisfaction; Satisfaction.IsSatisfied = Record.readInt(); - Satisfaction.ContainsErrors = Record.readInt(); if (!Satisfaction.IsSatisfied) { unsigned NumDetailRecords = Record.readInt(); for (unsigned i = 0; i != NumDetailRecords; ++i) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index aec3b7240ae99..5e5a86ee01a2b 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -402,7 +402,6 @@ static void addConstraintSatisfaction(ASTRecordWriter &Record, const ASTConstraintSatisfaction &Satisfaction) { Record.push_back(Satisfaction.IsSatisfied); - Record.push_back(Satisfaction.ContainsErrors); if (!Satisfaction.IsSatisfied) { Record.push_back(Satisfaction.NumRecords); for (const auto &DetailRecord : Satisfaction) { diff --git a/clang/test/SemaTemplate/concepts-recovery-expr.cpp b/clang/test/SemaTemplate/concepts-recovery-expr.cpp deleted file mode 100644 index 2f9d432ebac0e..0000000000000 --- a/clang/test/SemaTemplate/concepts-recovery-expr.cpp +++ /dev/null @@ -1,182 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -verify %s - -// expected-error@+1{{use of undeclared identifier 'b'}} -constexpr bool CausesRecoveryExpr = b; - -template -concept ReferencesCRE = CausesRecoveryExpr; - -template requires CausesRecoveryExpr // #NVC1REQ -void NoViableCands1(){} // #NVC1 - -template requires ReferencesCRE // #NVC2REQ -void NoViableCands2(){} // #NVC2 - -template // #NVC3REQ -void NoViableCands3(){} // #NVC3 - -void NVCUse() { - NoViableCands1(); - // expected-error@-1 {{no matching function for call to 'NoViableCands1'}} - // expected-note@#NVC1{{candidate template ignored: constraints not satisfied}} - // expected-note@#NVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - - NoViableCands2(); - // expected-error@-1 {{no matching function for call to 'NoViableCands2'}} - // expected-note@#NVC2{{candidate template ignored: constraints not satisfied}} - // expected-note@#NVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - NoViableCands3(); - // expected-error@-1 {{no matching function for call to 'NoViableCands3'}} - // expected-note@#NVC3{{candidate template ignored: constraints not satisfied}} - // expected-note@#NVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} -} - -template requires CausesRecoveryExpr // #OVC1REQ -void OtherViableCands1(){} // #OVC1 - -template -void OtherViableCands1(){} // #OVC1_ALT - -template requires ReferencesCRE // #OVC2REQ -void OtherViableCands2(){} // #OVC2 - -template -void OtherViableCands2(){} // #OVC2_ALT - -template // #OVC3REQ -void OtherViableCands3(){} // #OVC3 -template -void OtherViableCands3(){} // #OVC3_ALT - -void OVCUse() { - OtherViableCands1(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands1'}} - // expected-note@#OVC1_ALT {{candidate function}} - // expected-note@#OVC1 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - OtherViableCands2(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands2'}} - // expected-note@#OVC2_ALT {{candidate function}} - // expected-note@#OVC2 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - OtherViableCands3(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands3'}} - // expected-note@#OVC3_ALT {{candidate function}} - // expected-note@#OVC3 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} -} - -template requires CausesRecoveryExpr // #OBNVC1REQ -void OtherBadNoViableCands1(){} // #OBNVC1 - -template requires false // #OBNVC1REQ_ALT -void OtherBadNoViableCands1(){} // #OBNVC1_ALT - -template requires ReferencesCRE // #OBNVC2REQ -void OtherBadNoViableCands2(){} // #OBNVC2 - -template requires false// #OBNVC2REQ_ALT -void OtherBadNoViableCands2(){} // #OBNVC2_ALT - -template // #OBNVC3REQ -void OtherBadNoViableCands3(){} // #OBNVC3 -template requires false // #OBNVC3REQ_ALT -void OtherBadNoViableCands3(){} // #OBNVC3_ALT - -void OBNVCUse() { - OtherBadNoViableCands1(); - // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands1'}} - // expected-note@#OBNVC1_ALT {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC1REQ_ALT {{because 'false' evaluated to false}} - // expected-note@#OBNVC1 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - OtherBadNoViableCands2(); - // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands2'}} - // expected-note@#OBNVC2_ALT {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC2REQ_ALT {{because 'false' evaluated to false}} - // expected-note@#OBNVC2 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - OtherBadNoViableCands3(); - // expected-error@-1 {{no matching function for call to 'OtherBadNoViableCands3'}} - // expected-note@#OBNVC3_ALT {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC3REQ_ALT {{because 'false' evaluated to false}} - // expected-note@#OBNVC3 {{candidate template ignored: constraints not satisfied}} - // expected-note@#OBNVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} -} - - -// Same tests with member functions. -struct OVC { -template requires CausesRecoveryExpr // #MEMOVC1REQ -void OtherViableCands1(){} // #MEMOVC1 - -template -void OtherViableCands1(){} // #MEMOVC1_ALT - -template requires ReferencesCRE // #MEMOVC2REQ -void OtherViableCands2(){} // #MEMOVC2 - -template -void OtherViableCands2(){} // #MEMOVC2_ALT - -template // #MEMOVC3REQ -void OtherViableCands3(){} // #MEMOVC3 -template -void OtherViableCands3(){} // #MEMOVC3_ALT -}; - -void MemOVCUse() { - OVC S; - S.OtherViableCands1(); - // expected-error@-1 {{no matching member function for call to 'OtherViableCands1'}} - // expected-note@#MEMOVC1_ALT {{candidate function}} - // expected-note@#MEMOVC1 {{candidate template ignored: constraints not satisfied}} - // expected-note@#MEMOVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - S.OtherViableCands2(); - // expected-error@-1 {{no matching member function for call to 'OtherViableCands2'}} - // expected-note@#MEMOVC2_ALT {{candidate function}} - // expected-note@#MEMOVC2 {{candidate template ignored: constraints not satisfied}} - // expected-note@#MEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - S.OtherViableCands3(); - // expected-error@-1 {{no matching member function for call to 'OtherViableCands3'}} - // expected-note@#MEMOVC3_ALT {{candidate function}} - // expected-note@#MEMOVC3 {{candidate template ignored: constraints not satisfied}} - // expected-note@#MEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} -} - -struct StaticOVC { -template requires CausesRecoveryExpr // #SMEMOVC1REQ -static void OtherViableCands1(){} // #SMEMOVC1 - -template -static void OtherViableCands1(){} // #SMEMOVC1_ALT - -template requires ReferencesCRE // #SMEMOVC2REQ -static void OtherViableCands2(){} // #SMEMOVC2 - -template -static void OtherViableCands2(){} // #SMEMOVC2_ALT - -template // #SMEMOVC3REQ -static void OtherViableCands3(){} // #SMEMOVC3 -template -static void OtherViableCands3(){} // #SMEMOVC3_ALT -}; - -void StaticMemOVCUse() { - StaticOVC::OtherViableCands1(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands1'}} - // expected-note@#SMEMOVC1_ALT {{candidate function}} - // expected-note@#SMEMOVC1 {{candidate template ignored: constraints not satisfied}} - // expected-note@#SMEMOVC1REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - StaticOVC::OtherViableCands2(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands2'}} - // expected-note@#SMEMOVC2_ALT {{candidate function}} - // expected-note@#SMEMOVC2 {{candidate template ignored: constraints not satisfied}} - // expected-note@#SMEMOVC2REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} - StaticOVC::OtherViableCands3(); - // expected-error@-1 {{no matching function for call to 'OtherViableCands3'}} - // expected-note@#SMEMOVC3_ALT {{candidate function}} - // expected-note@#SMEMOVC3 {{candidate template ignored: constraints not satisfied}} - // expected-note@#SMEMOVC3REQ{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} -}