As reported in https://github.com/llvm/llvm-project/issues/54524, and
later in https://github.com/llvm/llvm-project/issues/60038, we were not
properly implmenting temp.constr.atomic P3. This patch stops implicitly
converting constraints to bool, and ensures the Rvalue conversion takes
place as needed.
Details
- Reviewers
tahonermann - Group Reviewers
Restricted Project Restricted Project - Commits
- rGb5d9f00b2096: Forbid implicit conversion of constraint expression to bool
Diff Detail
Unit Tests
Event Timeline
@ldionne @Mordante The libcxx failure isn't clear what it is complaining about, but I thought this fix might end up breaking a libcxx test, since it would be easy to fall into the trap of having an implicit conversion here.
Any chance you could prod at that test a little and see whose fault it is?
ALSO: NOTE TO SELF: need release note!
I think the problem is that __type_traits/common_reference.h doesn't re-export __type_traits/common_type.h in the modulemap. It should be enough to add export common_type to module common_reference (libcxx/include/module.modulemap.in:1399). See module is_arithmetic for an example. This is just a guess though, this stuff can be very weird.
Oh man, I hope the others know what you're talking about :) I don't really know how I caused this though :/
clang/lib/Sema/SemaConcept.cpp | ||
---|---|---|
379 | minor fix |
I've applied your patch locally and this diff fixes the issue:
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 5d4cf53aa334..30209b353d6b 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -747,7 +747,10 @@ module std [system] { module assignable { private header "__concepts/assignable.h" } module boolean_testable { private header "__concepts/boolean_testable.h" } module class_or_enum { private header "__concepts/class_or_enum.h" } - module common_reference_with { private header "__concepts/common_reference_with.h" } + module common_reference_with { + private header "__concepts/common_reference_with.h" + export type_traits.common_reference + } module common_with { private header "__concepts/common_with.h" } module constructible { private header "__concepts/constructible.h" } module convertible_to { private header "__concepts/convertible_to.h" }
I don't know why your patch changes the behaviour of clang here, but I wouldn't worry too much about it. There is a lot of weirdness around modules and dependent type names resulting in pretty much useless error messages. I hope the work on C++ modules reduces this weirdness, but I don't really know how that stuff works.
Speaking of: I guess the libcxx failure is NOT caused by me? https://reviews.llvm.org/D141992
I see this on a different review, despite this not being committed.
That's not great. Seems like some recently landed patch broke this. Do you mind committing the libc++-part of this patch to get the Clang CI green again? (Assuming the libc++ CI is green)
If this passes, I might just do the module-map patch as a separate commit to fix the CI, else the libcxx history is going to be awful strange :) I'm probably a bit from having this review approved anyway, as it is still 'night time' for most of my reviewers :)
The changes to the module map file seemed to make things worse! I reverted it for now, hoping this just goes green.
I see the current main pass for the module build in libc++. The error message seems different, from the message for missing parts of the module map. I'll dig a bit further to see whether I can find what's wrong.
I just tested locally with the latest nightly build
Debian clang version 16.0.0 (++20230116071901+2563ad8ef1a8-1~exp1~20230116072002.532) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin
and that passes the test that fails in the CI.
Can you test whether the issue occurs for you in HEAD without your patch.
@ldionne would it make sense to test the Clang CI in the scheduled build too, that would make pin-pointing a possible regression easier.
I don't have the libcxx build/tests set up in my environment anymore (and it was a bit of a hassle the last time, which was my motivation for asking @ldionne for pre-commit on clang patches :D ), so I don't really have the ability to run that test.
clang/lib/Sema/SemaConcept.cpp | ||
---|---|---|
367 | This comment appears to be unnecessary. | |
377–380 | ImplicitCastExpr::Create() has the following assertion. I wonder if we need to guard against this here. clang/lib/AST/Expr.cpp: 2073 assert((Kind != CK_LValueToRValue || 2074 !(T->isNullPtrType() || T->getAsCXXRecordDecl())) && 2075 "invalid type for lvalue-to-rvalue conversion"); Or perhaps it would be better to call Sema::DefaultLvalueConversion() here? | |
clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp | ||
4–5 | I'm not sure what this is intending to exercise. C isn't used elsewhere; this just appears to validate that a well-formed concept declaration is accepted (even if it is one that will always evaluate as false). I suggest modifying it to drop == 4 && !true and then validate that a diagnostic is issued (which might require a use of the concept). | |
29 | These tests look good. I think we should also exercise nested requirements to ensure that behavior is consistent: template<typename T> requires requires { requires S<T>{}; } void f3(T); void f3(int); Perhaps also add some examples where && does not denote a conjunction of atomic constraints. For example: template<typename T> requires (bool(1 && 2)) void f4(T); void f4(int); | |
libcxx/include/module.modulemap.in | ||
750–753 ↗ | (On Diff #490120) | I agree with this being done in a separate commit. |
clang/lib/Sema/SemaConcept.cpp | ||
---|---|---|
367 | Woops! I thought that wasn't mine :D | |
377–380 | I don't think we want all the baggage that DefaultLvalueConversion gets us, including diagnostics/etc. That assert IS concerning though... I presume we can come up with something to hit that. It DOES look like that DefeaultLValue conversion replaces the nullptrtypes with a NullToPointer cast, so perhaps I should do that, and doesn't do anything with a record type. | |
clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp | ||
4–5 | This is exactly out of the standard, which is why I copied it. however, a test for the diagnostic version seems like a good idea. |
Added tests suggested by Tom, also moved the cast creation after checking of the return type, so that we end up not hitting hte assert that Tom came up with. Added 2 tests that show the two conditions (that DID repro as a crash).
clang/lib/Sema/SemaConcept.cpp | ||
---|---|---|
377–380 | I'm surprised the additional checks for nullptr aren't tripping that assert; it looks to me like it should. Any ideas? |
clang/lib/Sema/SemaConcept.cpp | ||
---|---|---|
377–380 | I moved the creation of this AFTER 'CheckConstraintExpression', which will fail unless the type is 'bool' already. SO the expression here cannot be a nullptr or struct type. Before I moved it and wrote the new tests (NullTy and StructTy), it actually did hit the assert you mentioned. |
This comment appears to be unnecessary.