diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3370,8 +3370,9 @@ /// lvalue reference to the specified type. QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const { - assert(getCanonicalType(T) != OverloadTy && - "Unresolved overloaded function type"); + if (T->isPlaceholderType()) { + assert(T->isSpecificPlaceholderType(BuiltinType::UnknownAny) && "Unresolved placeholder type"); + } // Unique pointers, to guarantee there is only one pointer of a particular // structure. @@ -3409,6 +3410,10 @@ /// getRValueReferenceType - Return the uniqued reference to the type for an /// rvalue reference to the specified type. QualType ASTContext::getRValueReferenceType(QualType T) const { + if (T->isPlaceholderType()) { + assert(T->isSpecificPlaceholderType(BuiltinType::UnknownAny) && "Unresolved placeholder type"); + } + // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; 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 @@ -14320,7 +14320,8 @@ FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); UnbridgedCasts.restore(); - } else if (auto *UnresExpr = dyn_cast(NakedMemExpr)) { + } else { + UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); Qualifier = UnresExpr->getQualifier(); QualType ObjectType = UnresExpr->getBaseType(); @@ -14433,9 +14434,7 @@ } MemExpr = cast(MemExprE->IgnoreParens()); - } else - // Unimaged NakedMemExpr type. - return ExprError(); + } QualType ResultType = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1943,6 +1943,11 @@ if (ExprInst.isInvalid()) return nullptr; ExprResult TransExprRes = TransformExpr(E); + if (TransExprRes.isUsable() && !Trap.hasErrorOccurred()) { + if (TransExprRes.get()->hasPlaceholderType()) { + TransExprRes = SemaRef.CheckPlaceholderExpr(TransExprRes.get()); + } + } if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) TransExpr = createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) { E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); 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 @@ -12494,6 +12494,8 @@ TransExpr = Req->getExprSubstitutionDiagnostic(); else { ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr()); + if (TransExprRes.isUsable() && TransExprRes.get()->hasPlaceholderType()) + TransExprRes = SemaRef.CheckPlaceholderExpr(TransExprRes.get()); if (TransExprRes.isInvalid()) return nullptr; TransExpr = TransExprRes.get(); diff --git a/clang/test/SemaTemplate/constraints.cpp b/clang/test/SemaTemplate/constraints.cpp --- a/clang/test/SemaTemplate/constraints.cpp +++ b/clang/test/SemaTemplate/constraints.cpp @@ -24,35 +24,3 @@ // FIXME: These diagnostics are excessive. static_assert(test == 1); // expected-note 2{{while}} expected-note 2{{during}} } - -namespace PR52905 { -// A mock for std::convertible_to. Not complete support. -template -concept convertible_to = __is_convertible_to(_From, _To); // expected-note {{evaluated to false}} - -template -class A { -public: - using iterator = void **; - - iterator begin(); - const iterator begin() const; -}; - -template -concept Beginable1 = requires(T t) { - { t.begin } - ->convertible_to; // expected-note {{not satisfied}} -}; - -static_assert(Beginable1>); // expected-error {{static_assert failed}} - // expected-note@-1 {{does not satisfy 'Beginable1'}} - -template -concept Beginable2 = requires(T t) { - { t.begin() } - ->convertible_to; -}; - -static_assert(Beginable2>); -} // namespace PR52905 diff --git a/clang/test/SemaTemplate/pr52909.cpp b/clang/test/SemaTemplate/pr52909.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaTemplate/pr52909.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++2b -verify %s + +namespace PR52905 { +template concept C = true; + +struct A { + int begin(); + int begin() const; +}; + +template +concept Beginable = requires (T t) { + { t.begin } -> C; + // expected-note@-1 {{because 't.begin' would be invalid: reference to non-static member function must be called}} +}; + +static_assert(Beginable); // expected-error {{static_assert failed}} + // expected-note@-1 {{does not satisfy 'Beginable'}} +} // namespace PR52905 + +namespace PR52909a { + +template constexpr bool B = true; +template concept True = B; + +template +int foo(T t) requires requires { // expected-note {{candidate template ignored: constraints not satisfied}} + {t.begin} -> True; // expected-note {{because 't.begin' would be invalid: reference to non-static member function must be called}} +} +{} + +struct A { int begin(); }; +auto x = foo(A()); // expected-error {{no matching function for call to 'foo'}} + +} // namespace PR52909a + +namespace PR52909b { + +template concept True = true; + +template concept C = requires { + { T::begin } -> True; // expected-note {{because 'T::begin' would be invalid: reference to overloaded function could not be resolved}} +}; + +struct A { + static void begin(int); + static void begin(double); +}; + +static_assert(C); // expected-error {{static_assert failed}} + // expected-note@-1 {{because 'PR52909b::A' does not satisfy 'C'}} + +} // namespace PR52909b + +namespace PR53075 { +template concept True = true; + +template concept C = requires { + { &T::f } -> True; // expected-note {{because '&T::f' would be invalid: reference to overloaded function could not be resolved}} +}; + +struct S { + int *f(); + int *f() const; +}; + +static_assert(C); // expected-error {{static_assert failed}} + // expected-note@-1 {{because 'PR53075::S' does not satisfy 'C'}} + +} // namespace PR53075