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 @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" @@ -1363,7 +1364,19 @@ ExprResult TransformRequiresExpr(RequiresExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformRequiresExpr(E); + ExprResult TransReq = inherited::TransformRequiresExpr(E); + { + if (TransReq.isInvalid() || !E->getBody()->isDependentContext()) + return TransReq; + Sema::SFINAETrap Trap(SemaRef); + // We recreated parameters, but not by instantiating them. There may be + // pending access-dependent diagnostics to produce. + // RequiresExpr Body serves as the DeclContext for the parameters. + SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs); + if (Trap.hasErrorOccurred()) + return ExprError(); + } + return TransReq; } bool TransformRequiresExprRequirements( diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp @@ -104,3 +104,54 @@ constexpr bool b = requires (X &x) { static_cast(nullptr); }; // expected-error@-1{{constraint variable 'x' cannot be used in an evaluated context}} // expected-note@-2{{'x' declared here}} + +namespace access_checks { +template +struct A { + static constexpr bool foo(); + static constexpr bool bar(); + static constexpr bool baz(); + static constexpr bool faz(); +}; + +class C{}; + +class B { + void p() {} + bool data_member = true; + static const bool static_member = true; + friend struct A<0>; +}; + +template +constexpr bool A::foo() { + return requires(B b) { b.p(); }; +} +static_assert(!A<1>::foo()); +static_assert(A<0>::foo()); + +template +constexpr bool A::bar() { + return requires() { B::static_member; }; +} +static_assert(!A<1>::bar()); +static_assert(A<0>::bar()); + +template +constexpr bool A::baz() { + return requires(B b) { b.data_member; }; +} +static_assert(!A<1>::baz()); +static_assert(A<0>::baz()); + +template +constexpr bool A::faz() { + return requires(B a, B b) { + a.p(); + b.data_member; + B::static_member; + }; +} +static_assert(!A<1>::faz()); +static_assert(A<0>::faz()); +} \ No newline at end of file