llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Adam Dangoor (adamtheturtle) <details> <summary>Changes</summary> A discarded enable_if candidate eagerly formats the substituted condition for its failure diagnostic. For a small nested type with repeated default template arguments, pretty-printing that condition dominates a valid call that ultimately selects the fallback overload. Keep the failed condition as an expression in the partial diagnostic and format it when diagnosing a rejected candidate. Condition evaluation and candidate viability remain unchanged. Add a qualified-call regression that excludes ADL and has no standard-library dependency. Fixes #<!-- -->235703. Validation on macOS arm64 with assertions enabled, built independently against LLVM main `0a6c7b28e6a5ad99b4d564908a6dd0912f944328`: - `clang`, `clang-tidy`, `clang-format`, and `FileCheck` build passed. - Formatting checked with the compiler build's clang-format. - sfinae: 13 upstream lit tests passed. The original Linux AArch64 LLVM 23.1.4 measurements are in the linked issue. Those are single wall-clock samples, not statistical benchmarks. Prepared with AI assistance (OpenAI Codex). --- Full diff: https://github.com/llvm/llvm-project/pull/235715.diff 3 Files Affected: - (modified) clang/lib/Sema/SemaOverload.cpp (+9-1) - (modified) clang/lib/Sema/SemaTemplate.cpp (+23-20) - (added) clang/test/SemaTemplate/enable-if-discarded-deep-diagnostic.cpp (+12) ``````````diff diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index c56f8127834a51..6fe31952c82c88 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12724,9 +12724,17 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, // We found a specific requirement that disabled the enable_if. if (PDiag && PDiag->second.getDiagID() == diag::err_typename_nested_not_found_requirement) { + auto *Storage = PDiag->second.getStorage(); + std::string Description; + if (Storage->DiagArgumentsKind[0] == DiagnosticsEngine::ak_expr) { + auto *Cond = reinterpret_cast<Expr *>(Storage->DiagArgumentsVal[0]); + Description = S.findFailedBooleanCondition(Cond).second; + } else { + Description = PDiag->second.getStringArg(0).str(); + } S.Diag(Templated->getLocation(), diag::note_ovl_candidate_disabled_by_requirement) - << PDiag->second.getStringArg(0) << TemplateArgString; + << Description << TemplateArgString; return; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ec1f8077893eb3..e78b3026692933 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3718,9 +3718,8 @@ class FailedBooleanConditionPrinterHelper : public PrinterHelper { } // end anonymous namespace -std::pair<Expr *, std::string> -Sema::findFailedBooleanCondition(Expr *Cond) { - Cond = lookThroughRangesV3Condition(PP, Cond); +static Expr *findFailedBooleanConditionExpr(Sema &S, Expr *Cond) { + Cond = lookThroughRangesV3Condition(S.getPreprocessor(), Cond); // Separate out all of the terms in a conjunction. SmallVector<Expr *, 4> Terms; @@ -3739,11 +3738,10 @@ Sema::findFailedBooleanCondition(Expr *Cond) { // The initialization of the parameter from the argument is // a constant-evaluated context. EnterExpressionEvaluationContext ConstantEvaluated( - *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); bool Succeeded; - if (Term->EvaluateAsBooleanCondition(Succeeded, Context) && - !Succeeded) { + if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) && !Succeeded) { FailedCond = TermAsWritten; break; } @@ -3751,6 +3749,11 @@ Sema::findFailedBooleanCondition(Expr *Cond) { if (!FailedCond) FailedCond = Cond->IgnoreParenImpCasts(); + return FailedCond; +} + +std::pair<Expr *, std::string> Sema::findFailedBooleanCondition(Expr *Cond) { + Expr *FailedCond = findFailedBooleanConditionExpr(*this, Cond); std::string Description; { llvm::raw_string_ostream Out(Description); @@ -3927,10 +3930,10 @@ QualType Sema::CheckTemplateIdType(ElaboratedTypeKeyword Keyword, diag::err_typename_nested_not_found_enable_if && TemplateArgs[0].getArgument().getKind() == TemplateArgument::Expression) { - Expr *FailedCond; - std::string FailedDescription; - std::tie(FailedCond, FailedDescription) = - findFailedBooleanCondition(TemplateArgs[0].getSourceExpression()); + // Keep the expression until a failed candidate is diagnosed. + // Formatting canonical types here expands discarded candidates. + Expr *FailedCond = findFailedBooleanConditionExpr( + *this, TemplateArgs[0].getSourceExpression()); // Remove the old SFINAE diagnostic. PartialDiagnosticAt OldDiag = @@ -3942,7 +3945,7 @@ QualType Sema::CheckTemplateIdType(ElaboratedTypeKeyword Keyword, DeductionInfo->addSFINAEDiagnostic( OldDiag.first, PDiag(diag::err_typename_nested_not_found_requirement) - << FailedDescription << FailedCond->getSourceRange()); + << FailedCond << FailedCond->getSourceRange()); } } } @@ -11521,15 +11524,15 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we have a condition, narrow it down to the specific failed // condition. if (Cond) { - Expr *FailedCond; - std::string FailedDescription; - std::tie(FailedCond, FailedDescription) = - findFailedBooleanCondition(Cond); - - Diag(FailedCond->getExprLoc(), - diag::err_typename_nested_not_found_requirement) - << FailedDescription - << FailedCond->getSourceRange(); + Expr *FailedCond = findFailedBooleanConditionExpr(*this, Cond); + + auto DB = Diag(FailedCond->getExprLoc(), + diag::err_typename_nested_not_found_requirement); + if (getSFINAEContext()) + DB << FailedCond; + else + DB << findFailedBooleanCondition(FailedCond).second; + DB << FailedCond->getSourceRange(); return QualType(); } diff --git a/clang/test/SemaTemplate/enable-if-discarded-deep-diagnostic.cpp b/clang/test/SemaTemplate/enable-if-discarded-deep-diagnostic.cpp new file mode 100644 index 00000000000000..ad99cf6990467b --- /dev/null +++ b/clang/test/SemaTemplate/enable-if-discarded-deep-diagnostic.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// expected-no-diagnostics + +namespace std { +template<bool, class T=void> struct enable_if {}; +template<class T> struct enable_if<true,T> { using type=T; }; +template<bool B, class T=void> using enable_if_t=typename enable_if<B,T>::type; +} +template<class T, class U=T> struct Node {}; +template<class T, std::enable_if_t<(sizeof(T) == 0), int> = 0> void accept(T) {} +void accept(...) {} +int main() { ::accept(Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<int>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>{}); } `````````` </details> https://github.com/llvm/llvm-project/pull/235715 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
