Skip to content

Commit 57faae4

Browse files
zyn0217tomtor
authored andcommitted
[Clang] Fail the constraint substitution early after CWG2369 (llvm#143096)
CWG2369 revealed another case where we were SFINAE'ing out the invalid result of substitution, but the expression now makes the way into evaluation. We switch to the concept specialization's context before we check it. This ensures that we're able to realize the invalid expression earlier, so we can avoid evaluating invalid expression, which is a hard error. This also fixes llvm#115838
1 parent 6a8c99f commit 57faae4

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,7 @@ Bug Fixes to C++ Support
833833
- Fixed an access checking bug when initializing non-aggregates in default arguments (#GH62444), (#GH83608)
834834
- Fixed a pack substitution bug in deducing class template partial specializations. (#GH53609)
835835
- Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835)
836+
- Fixed an access checking bug when substituting into concepts (#GH115838)
836837

837838
Bug Fixes to AST Handling
838839
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4749,6 +4749,8 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
47494749
EnterExpressionEvaluationContext EECtx{
47504750
*this, ExpressionEvaluationContext::Unevaluated, CSD};
47514751

4752+
ContextRAII CurContext(*this, CSD->getDeclContext(),
4753+
/*NewThisContext=*/false);
47524754
if (!AreArgsDependent &&
47534755
CheckConstraintSatisfaction(
47544756
NamedConcept, AssociatedConstraint(NamedConcept->getConstraintExpr()),

clang/test/SemaTemplate/concepts.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,3 +1200,57 @@ bool test_val_types() {
12001200
}
12011201

12021202
}
1203+
1204+
namespace CWG2369_Regression {
1205+
1206+
enum class KindEnum {
1207+
Unknown = 0,
1208+
Foo = 1,
1209+
};
1210+
1211+
template <typename T>
1212+
concept KnownKind = T::kind() != KindEnum::Unknown;
1213+
1214+
template <KnownKind T> struct KnownType;
1215+
1216+
struct Type {
1217+
KindEnum kind() const;
1218+
1219+
static Type f(Type t);
1220+
1221+
template <KnownKind T> static KnownType<T> f(T t);
1222+
1223+
static void g() {
1224+
Type t;
1225+
f(t);
1226+
}
1227+
};
1228+
1229+
template <KnownKind T> struct KnownType {
1230+
static constexpr KindEnum kind() { return KindEnum::Foo; }
1231+
};
1232+
1233+
}
1234+
1235+
namespace GH115838 {
1236+
1237+
template<typename T> concept has_x = requires(T t) {{ t.x };};
1238+
1239+
class Publ { public: int x = 0; };
1240+
class Priv { private: int x = 0; };
1241+
class Prot { protected: int x = 0; };
1242+
class Same { protected: int x = 0; };
1243+
1244+
template<typename T> class D;
1245+
template<typename T> requires ( has_x<T>) class D<T>: public T { public: static constexpr bool has = 1; };
1246+
template<typename T> requires (!has_x<T>) class D<T>: public T { public: static constexpr bool has = 0; };
1247+
1248+
// "Same" is identical to "Prot" but queried before used.
1249+
static_assert(!has_x<Same>, "Protected should be invisible.");
1250+
static_assert(!D<Same>::has, "Protected should be invisible.");
1251+
1252+
static_assert( D<Publ>::has, "Public should be visible.");
1253+
static_assert(!D<Priv>::has, "Private should be invisible.");
1254+
static_assert(!D<Prot>::has, "Protected should be invisible.");
1255+
1256+
}

0 commit comments

Comments
 (0)