diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -84,6 +84,13 @@ const ConstraintSatisfaction *Satisfaction, bool Dependent, bool ContainsUnexpandedParameterPack); + static ConceptSpecializationExpr * + CreateWithSFINAE(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, + const ConstraintSatisfaction *Satisfaction); + ArrayRef<TemplateArgument> getTemplateArguments() const { return SpecDecl->getTemplateArguments(); } diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -844,12 +844,13 @@ auto TA = TemplateArgumentDependence::None; const auto InterestingDeps = TemplateArgumentDependence::Instantiation | TemplateArgumentDependence::UnexpandedPack; - for (const TemplateArgumentLoc &ArgLoc : - E->getTemplateArgsAsWritten()->arguments()) { - TA |= ArgLoc.getArgument().getDependence() & InterestingDeps; - if (TA == InterestingDeps) - break; - } + if (E->getTemplateArgsAsWritten()) + for (const TemplateArgumentLoc &ArgLoc : + E->getTemplateArgsAsWritten()->arguments()) { + TA |= ArgLoc.getArgument().getDependence() & InterestingDeps; + if (TA == InterestingDeps) + break; + } ExprDependence D = ValueDependent ? ExprDependence::Value : ExprDependence::None; diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -103,6 +103,16 @@ Dependent, ContainsUnexpandedParameterPack); } +ConceptSpecializationExpr *ConceptSpecializationExpr::CreateWithSFINAE( + const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ConstraintSatisfaction *Satisfaction) { + return ConceptSpecializationExpr::Create( + C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, nullptr, + nullptr, Satisfaction); +} + const TypeConstraint * concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const { assert(isTypeConstraint()); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3477,6 +3477,22 @@ return Result; } + ExprResult RebuildConceptSpecializationExprWithSFINAE( + ConceptSpecializationExpr *E, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept) { + ConstraintSatisfaction Satisfaction; + Satisfaction.IsSatisfied = false; + Satisfaction.ContainsErrors = true; + CXXScopeSpec SS; + SS.Adopt(NNS); + return ConceptSpecializationExpr::CreateWithSFINAE( + SemaRef.Context, + SS.isSet() ? SS.getWithLocInContext(SemaRef.Context) + : NestedNameSpecifierLoc{}, + TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, &Satisfaction); + } + /// \brief Build a new requires expression. /// /// By default, performs semantic analysis to build the new expression. @@ -12617,9 +12633,20 @@ ConceptSpecializationExpr *E) { const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten(); TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc); - if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), - Old->NumTemplateArgs, TransArgs)) - return ExprError(); + { + Sema::SFINAETrap Trap(getSema()); + if (getDerived().TransformTemplateArguments( + Old->getTemplateArgs(), Old->NumTemplateArgs, TransArgs) && + !Trap.hasErrorOccurred()) + return ExprError(); + + if (Trap.hasErrorOccurred()) { + // FIXME: Propogate detailed subtitution falilure diagnostics. + return getDerived().RebuildConceptSpecializationExprWithSFINAE( + E, E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), + E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept()); + } + } return getDerived().RebuildConceptSpecializationExpr( E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), 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 @@ -764,3 +764,53 @@ __iterator_traits_member_pointer_or_arrow_or_void<counted_iterator<int>> f; } }// namespace InheritedFromPartialSpec + +namespace nested_requirements { +template<class T> concept True = true; + +struct S { double value; }; + +template <class T> +concept Pipes = requires (T x) { + requires True<decltype(x.value)> || True<T>; + requires True<T> || True<decltype(x.value)>; +}; +template <class T> +concept Amps1 = requires (T x) { + requires True<decltype(x.value)> && True<T>; + // expected-note@-1{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} +}; +template <class T> +concept Amps2 = requires (T x) { + requires True<T> && True<decltype(x.value)>; +}; + +static_assert(Pipes<S>); +static_assert(Pipes<double>); + +static_assert(Amps1<S>); +static_assert(!Amps1<double>); + +static_assert(Amps2<S>); +static_assert(!Amps2<double>); + +template<class T> +void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}} + requires + True<decltype(x.value)> // expected-note {{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}} + && True<T>; +} {} +template<class T> void fooPipes() requires Pipes<T> {} +template<class T> void fooAmps1() requires Amps1<T> {} +// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \ +// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}} + +void foo() { + foo1<S>(); + foo1<int>(); // expected-error {{no matching function for call to 'foo1'}} + fooPipes<S>(); + fooPipes<int>(); + fooAmps1<S>(); + fooAmps1<int>(); // expected-error {{no matching function for call to 'fooAmps1'}} +} +} \ No newline at end of file