-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[Clang] Add detailed notes explaining why is_constructible
evaluates to false (Revert 16d5db7)
#151935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…alse. Updated the diagnostics checks in libc++ tests. (llvm#144220) Added explanation why a is constructible evaluated to false. Also fixed problem with ExtractTypeTraitFromExpression. In case std::is_xxx_v<> with variadic pack it tries to get template argument, but fails in expression Arg.getAsType() due to Arg.getKind() == TemplateArgument::ArgKind::Pack, but not TemplateArgument::ArgKind::Type. Reverts llvm#144127 Fixies llvm#143309 (comment)
@llvm/pr-subscribers-clang @llvm/pr-subscribers-libcxx Author: Corentin Jabot (cor3ntin) ChangesAdds explanation why This reapplies as-is e476f96. The test failure in libc++ is interesting in that, in the absence of nested diagnostics a bunch of diagnostics are emitted as error instead of notes, which we cannot silence with The fix here is to prevent the diagnostics to be emitted in the first place. Fixes #150601 Patch is 30.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151935.diff 15 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0ba06d6f2dee3..24b3cf1213faa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1812,7 +1812,10 @@ def note_unsatisfied_trait_reason
"%DeletedAssign{has a deleted %select{copy|move}1 "
"assignment operator}|"
"%UnionWithUserDeclaredSMF{is a union with a user-declared "
- "%sub{select_special_member_kind}1}"
+ "%sub{select_special_member_kind}1}|"
+ "%FunctionType{is a function type}|"
+ "%CVVoidType{is a cv void type}|"
+ "%IncompleteArrayType{is an incomplete array type}"
"}0">;
def warn_consteval_if_always_true : Warning<
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index c2f0600295e9e..1d8687e4bf1c1 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TypeTraits.h"
@@ -1963,6 +1965,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
.Case("is_assignable", TypeTrait::BTT_IsAssignable)
.Case("is_empty", TypeTrait::UTT_IsEmpty)
.Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout)
+ .Case("is_constructible", TypeTrait::TT_IsConstructible)
.Default(std::nullopt);
}
@@ -1999,8 +2002,16 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
Trait = StdNameToTypeTrait(Name);
if (!Trait)
return std::nullopt;
- for (const auto &Arg : VD->getTemplateArgs().asArray())
- Args.push_back(Arg.getAsType());
+ for (const auto &Arg : VD->getTemplateArgs().asArray()) {
+ if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
+ for (const auto &InnerArg : Arg.pack_elements())
+ Args.push_back(InnerArg.getAsType());
+ } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
+ Args.push_back(Arg.getAsType());
+ } else {
+ llvm_unreachable("Unexpected kind");
+ }
+ }
return {{Trait.value(), std::move(Args)}};
}
@@ -2273,6 +2284,60 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
}
}
+static void DiagnoseNonConstructibleReason(
+ Sema &SemaRef, SourceLocation Loc,
+ const llvm::SmallVector<clang::QualType, 1> &Ts) {
+ if (Ts.empty()) {
+ return;
+ }
+
+ bool ContainsVoid = false;
+ for (const QualType &ArgTy : Ts) {
+ ContainsVoid |= ArgTy->isVoidType();
+ }
+
+ if (ContainsVoid)
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ QualType T = Ts[0];
+ if (T->isFunctionType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::FunctionType;
+
+ if (T->isIncompleteArrayType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::IncompleteArrayType;
+
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+ if (!D || D->isInvalidDecl() || !D->hasDefinition())
+ return;
+
+ llvm::BumpPtrAllocator OpaqueExprAllocator;
+ SmallVector<Expr *, 2> ArgExprs;
+ ArgExprs.reserve(Ts.size() - 1);
+ for (unsigned I = 1, N = Ts.size(); I != N; ++I) {
+ QualType ArgTy = Ts[I];
+ if (ArgTy->isObjectType() || ArgTy->isFunctionType())
+ ArgTy = SemaRef.Context.getRValueReferenceType(ArgTy);
+ ArgExprs.push_back(
+ new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+ OpaqueValueExpr(Loc, ArgTy.getNonLValueExprType(SemaRef.Context),
+ Expr::getValueKindForType(ArgTy)));
+ }
+
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::ContextRAII TUContext(SemaRef,
+ SemaRef.Context.getTranslationUnitDecl());
+ InitializedEntity To(InitializedEntity::InitializeTemporary(T));
+ InitializationKind InitKind(InitializationKind::CreateDirect(Loc, Loc, Loc));
+ InitializationSequence Init(SemaRef, To, InitKind, ArgExprs);
+
+ Init.Diagnose(SemaRef, To, InitKind, ArgExprs);
+ SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
SourceLocation Loc, QualType T) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
@@ -2559,6 +2624,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case UTT_IsStandardLayout:
DiagnoseNonStandardLayoutReason(*this, E->getBeginLoc(), Args[0]);
break;
+ case TT_IsConstructible:
+ DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
+ break;
default:
break;
}
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 5b4551ba0143b..9948075852135 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -564,11 +564,12 @@ struct A {
namespace ex2 {
#if __cplusplus >= 201103L
struct Bar {
- struct Baz {
+ struct Baz { // #cwg1890-Baz
int a = 0;
};
static_assert(__is_constructible(Baz), "");
// since-cxx11-error@-1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
+ // since-cxx11-note@#cwg1890-Baz {{'Baz' defined here}}
};
#endif
} // namespace ex2
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 8b469dd22943a..135865c8450f5 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -80,21 +80,30 @@ struct ImplicitlyCopyable {
static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&));
-struct Movable {
+struct Movable { // #Movable
template <typename T>
requires __is_constructible(Movable, T) // #err-self-constraint-1
- explicit Movable(T op) noexcept; // #1
- Movable(Movable&&) noexcept = default; // #2
+ explicit Movable(T op) noexcept; // #Movable1
+ Movable(Movable&&) noexcept = default; // #Movable2
};
static_assert(__is_constructible(Movable, Movable&&));
static_assert(__is_constructible(Movable, const Movable&));
-// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}}
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} \
+// expected-error@-1 {{call to implicitly-deleted copy constructor of 'Movable'}} \
+// expected-note@#Movable {{'Movable' defined here}} \
+// expected-note@#Movable {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Movable' for 1st argument}} \
+// expected-note@#Movable2 {{copy constructor is implicitly deleted because 'Movable' has a user-declared move constructor}} \
+// expected-note@#Movable2 {{candidate constructor not viable: no known conversion from 'int' to 'Movable' for 1st argument}} \
+// expected-note@#Movable1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+
static_assert(__is_constructible(Movable, int));
-// expected-error@-1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'Movable'}} \
// expected-note@-1 2{{}}
// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
// expected-note@#err-self-constraint-1 4{{}}
+// expected-note@#Movable {{'Movable' defined here}}
template <typename T>
struct Members {
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index cf33ac283ab42..f3ddbbfe15bdc 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -42,6 +42,14 @@ static constexpr bool value = __is_standard_layout(T);
};
template <typename T>
constexpr bool is_standard_layout_v = __is_standard_layout(T);
+
+template <typename... Args>
+struct is_constructible {
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
#ifdef STD2
@@ -97,6 +105,17 @@ template <typename T>
using is_standard_layout = __details_is_standard_layout<T>;
template <typename T>
constexpr bool is_standard_layout_v = __is_standard_layout(T);
+
+template <typename... Args>
+struct __details_is_constructible{
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
@@ -149,6 +168,15 @@ template <typename T>
using is_standard_layout = __details_is_standard_layout<T>;
template <typename T>
constexpr bool is_standard_layout_v = is_standard_layout<T>::value;
+
+template <typename... Args>
+struct __details_is_constructible : bool_constant<__is_constructible(Args...)> {};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = is_constructible<Args...>::value;
#endif
}
@@ -211,6 +239,15 @@ static_assert(std::is_assignable_v<int&, void>);
// expected-error@-1 {{static assertion failed due to requirement 'std::is_assignable_v<int &, void>'}} \
// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
+static_assert(std::is_constructible<int, int>::value);
+
+static_assert(std::is_constructible<void>::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
+// expected-note@-1 {{because it is a cv void type}}
+static_assert(std::is_constructible_v<void>);
+// expected-error@-1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
namespace test_namespace {
using namespace std;
static_assert(is_trivially_relocatable<int&>::value);
@@ -256,6 +293,13 @@ namespace test_namespace {
// expected-error@-1 {{static assertion failed due to requirement 'is_empty_v<int &>'}} \
// expected-note@-1 {{'int &' is not empty}} \
// expected-note@-1 {{because it is a reference type}}
+
+ static_assert(is_constructible<void>::value);
+ // expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
+ // expected-note@-1 {{because it is a cv void type}}
+ static_assert(is_constructible_v<void>);
+ // expected-error@-1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
+ // expected-note@-1 {{because it is a cv void type}}
}
@@ -284,6 +328,15 @@ concept C4 = std::is_assignable_v<T, U>; // #concept8
template <C4<void> T> void g4(); // #cand8
+template <typename... Args>
+requires std::is_constructible<Args...>::value void f3(); // #cand5
+
+template <typename... Args>
+concept C3 = std::is_constructible_v<Args...>; // #concept6
+
+template <C3 T> void g3(); // #cand6
+
+
void test() {
f<int&>();
// expected-error@-1 {{no matching function for call to 'f'}} \
@@ -327,6 +380,19 @@ void test() {
// expected-note@#cand8 {{because 'C4<int &, void>' evaluated to false}} \
// expected-note@#concept8 {{because 'std::is_assignable_v<int &, void>' evaluated to false}} \
// expected-error@#concept8 {{assigning to 'int' from incompatible type 'void'}}
+
+ f3<void>();
+ // expected-error@-1 {{no matching function for call to 'f3'}} \
+ // expected-note@#cand5 {{candidate template ignored: constraints not satisfied [with Args = <void>]}} \
+ // expected-note-re@#cand5 {{because '{{.*}}is_constructible<void>::value' evaluated to false}} \
+ // expected-note@#cand5 {{because it is a cv void type}}
+
+ g3<void>();
+ // expected-error@-1 {{no matching function for call to 'g3'}} \
+ // expected-note@#cand6 {{candidate template ignored: constraints not satisfied [with T = void]}} \
+ // expected-note@#cand6 {{because 'void' does not satisfy 'C3'}} \
+ // expected-note@#concept6 {{because 'std::is_constructible_v<void>' evaluated to false}} \
+ // expected-note@#concept6 {{because it is a cv void type}}
}
}
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index cc923d206ab35..54806a93ddf80 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -489,6 +489,68 @@ static_assert(__is_trivially_copyable(S12));
// expected-note@#tc-S12 {{'S12' defined here}}
}
+namespace constructible {
+
+struct S1 { // #c-S1
+ S1(int); // #cc-S1
+};
+static_assert(__is_constructible(S1, char*));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S1'}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'char *' to 'const S1' for 1st argument}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'char *' to 'S1' for 1st argument}} \
+// expected-note@#cc-S1 {{candidate constructor not viable: no known conversion from 'char *' to 'int' for 1st argument; dereference the argument with *}} \
+// expected-note@#c-S1 {{'S1' defined here}}
+
+struct S2 { // #c-S2
+ S2(int, float, double); // #cc-S2
+};
+static_assert(__is_constructible(S2, float));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'float' to 'const S2' for 1st argument}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'float' to 'S2' for 1st argument}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 1 was provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(S2, float, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float, void)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@-1{{because it is a cv void type}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 2 were provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(int[]));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int[])'}} \
+// expected-note@-1 {{because it is an incomplete array type}}
+
+static_assert(__is_constructible(void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(void, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void, void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(const void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(volatile void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(int ()));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
+// expected-note@-1 {{because it is a function type}}
+
+static_assert(__is_constructible(void (int, float)));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
+// expected-note@-1 {{because it is a function type}}
+}
+
namespace assignable {
struct S1;
static_assert(__is_assignable(S1&, const S1&));
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 0f446b870723b..5061e1703ed15 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -845,7 +845,7 @@ class expected : private __expected_base<_Tp, _Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
- static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
+ static_assert(bool(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error())))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
@@ -854,7 +854,7 @@ class expected : private __expected_base<_Tp, _Err> {
}
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
- static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>,
+ static_assert(bool(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error())))>,
"error_type has to be both copy constructible and constructible from decltype(std::move(error()))");
if (!this->__has_val()) {
std::__throw_bad_expected_access<_Err>(std::move(error()));
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
index c46ab633295c1..fbd2317ebeee2 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
@@ -55,6 +55,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* 0-1{{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -74,6 +75,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* 0-1{{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -94,6 +96,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initializ...
[truncated]
|
@egorshamshura FYI |
✅ With the latest revision this PR passed the C/C++ code formatter. |
50c7eff
to
5d99930
Compare
Thanks for your help. I could not figure it out quickly on my own, and then life got in the way and I forgot... So I hope to return to implementing some more type traits diagnostic in the near future. @_@ |
@@ -43,6 +43,7 @@ void cant_construct_data_handle_type() { | |||
int data; | |||
std::mdspan<int, std::extents<int>, std::layout_right, convertible_accessor_but_not_handle<int>> m_nc(&data); | |||
// expected-error-re@*:* {{{{.*}}no matching constructor for initialization of {{.*}} (aka 'not_const_convertible_handle<const int>')}} | |||
// expected-error@*:* 0-1{{no matching constructor for initialization of 'not_const_convertible_handle<const int>'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Urg. Thanks for fixing these tests. They appear to be way to brittle to changes in compiler diagnostics.
@@ -55,6 +55,7 @@ void test() { | |||
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so these tests are a mess. libc++ shouldn't be using verify tests like this.
Given how brittle these tests are, and how little they actually meaningfully test today, I think it's fair to simply make them work again. However you can; let's just not modify the headers to work around these tests.
libcxx/include/__expected/expected.h
Outdated
@@ -845,7 +845,7 @@ class expected : private __expected_base<_Tp, _Err> { | |||
} | |||
|
|||
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { | |||
static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>, | |||
static_assert(bool(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's drop this change and work around the expected tests wholly within the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Adds explanation why
is_constructible
evaluates to false.This reapplies as-is e476f96.
This was reverted in 16d5db7 because of a test failure in libc++.
The test failure in libc++ is interesting in that, in the absence of nested diagnostics a bunch of diagnostics are emitted as error instead of notes, which we cannot silence with
-verify-ignore-unexpected
.The fix here is to prevent the diagnostics to be emitted in the first place.
However this is clearly not ideal and we should make sure to deploy a better solution in the clang 22 time frame, in the lines of https://discourse.llvm.org/t/rfc-add-a-new-text-diagnostics-format-that-supports-nested-diagnostics/87641/12
Fixes #150601