diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 1126c2c517fe48..2f5fb8f8d029ef 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -780,7 +780,9 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, const Expr *NewConstr) { if (OldConstr == NewConstr) return true; - if (Old && New && Old != New) { + // C++ [temp.constr.decl]p4 + if (Old && New && Old != New && + Old->getLexicalDeclContext() != New->getLexicalDeclContext()) { if (const Expr *SubstConstr = SubstituteConstraintExpression(*this, Old, OldConstr)) OldConstr = SubstConstr; diff --git a/clang/test/SemaTemplate/concepts-no-early-substitution.cpp b/clang/test/SemaTemplate/concepts-no-early-substitution.cpp new file mode 100644 index 00000000000000..9e576f16a263be --- /dev/null +++ b/clang/test/SemaTemplate/concepts-no-early-substitution.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++20 -x c++ %s -verify -fsyntax-only +// expected-no-diagnostics + +template +concept HasMemberBegin = requires(T0 t) { t.begin(); }; + +struct GetBegin { + template + void operator()(T1); +}; + +GetBegin begin; + +template +concept Concept = requires(T2 t) { begin(t); }; + +struct Subrange; + +template +struct View { + Subrange &getSubrange(); + + operator bool() + requires true; + + operator bool() + requires requires { begin(getSubrange()); }; + + void begin(); +}; + +struct Subrange : View {}; +static_assert(Concept);