Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1776,7 +1776,8 @@ def note_unsatisfied_trait
"%StandardLayout{standard-layout}|"
"%Aggregate{aggregate}|"
"%Final{final}|"
"%Abstract{abstract}"
"%Abstract{abstract}|"
"%Destructible{destructible}"
"}1">;

def note_unsatisfied_trait_reason
Expand Down Expand Up @@ -1808,6 +1809,7 @@ def note_unsatisfied_trait_reason
"%NonStandardLayoutMember{has a non-standard-layout member %1 of type %2}|"
"%IndirectBaseWithFields{has an indirect base %1 with data members}|"
"%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
"%InaccessibleDtr{has a %select{private|protected}1 destructor}|"
"%UserProvidedCtr{has a user provided %select{copy|move}1 "
"constructor}|"
"%UserDeclaredCtr{has a user-declared constructor}|"
Expand All @@ -1823,6 +1825,7 @@ def note_unsatisfied_trait_reason
"%FunctionType{is a function type}|"
"%CVVoidType{is a cv void type}|"
"%IncompleteArrayType{is an incomplete array type}|"
"%IncompleteType{is an incomplete type}|"
"%PrivateProtectedDirectDataMember{has a %select{private|protected}1 direct data member}|"
"%PrivateProtectedDirectBase{has a %select{private|protected}1 direct base}|"
"%NotClassOrUnion{is not a class or union type}|"
Expand Down
64 changes: 64 additions & 0 deletions clang/lib/Sema/SemaTypeTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2028,6 +2028,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
.Case("is_constructible", TypeTrait::TT_IsConstructible)
.Case("is_final", TypeTrait::UTT_IsFinal)
.Case("is_abstract", TypeTrait::UTT_IsAbstract)
.Case("is_destructible", TypeTrait::UTT_IsDestructible)
.Default(std::nullopt);
}

Expand Down Expand Up @@ -2399,6 +2400,66 @@ static void DiagnoseNonConstructibleReason(
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
}

static void DiagnoseNonDestructibleReason(Sema &SemaRef, SourceLocation Loc,
QualType T) {

QualType CoreT = T.getCanonicalType();
if (const ArrayType *AT = SemaRef.Context.getAsArrayType(CoreT))
CoreT = AT->getElementType();

SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
<< CoreT << diag::TraitName::Destructible;

if (CoreT->isFunctionType()) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::FunctionType;
return;
}

if (CoreT->isVoidType()) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::CVVoidType;
return;
}

if (CoreT->isIncompleteType()) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::IncompleteType;
return;
}

const CXXRecordDecl *RD = CoreT->getAsCXXRecordDecl();
if (!RD || RD->isInvalidDecl())
return;

const CXXRecordDecl *Def = RD->getDefinition();
if (!Def) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::IncompleteType;
return;
}

CXXDestructorDecl *Dtor = Def->getDestructor();
if (!Dtor)
return;

if (Dtor->isDeleted()) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::DeletedDtr << 0
<< Dtor->getSourceRange();
return;
}

AccessSpecifier AS = Dtor->getAccess();
if (AS == AS_private || AS == AS_protected) {
unsigned Select = (AS == AS_private) ? 0 : 1;
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::InaccessibleDtr << Select
<< Dtor->getSourceRange();
return;
}
}

static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
SourceLocation Loc, QualType T) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
Expand Down Expand Up @@ -2889,6 +2950,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case TT_IsConstructible:
DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
break;
case UTT_IsDestructible:
DiagnoseNonDestructibleReason(*this, E->getBeginLoc(), Args[0]);
break;
case UTT_IsAggregate:
DiagnoseNonAggregateReason(*this, E->getBeginLoc(), Args[0]);
break;
Expand Down
76 changes: 76 additions & 0 deletions clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ struct is_abstract {
template <typename T>
constexpr bool is_abstract_v = __is_abstract(T);

template <typename T>
struct is_destructible {
static constexpr bool value = __is_destructible(T);
};

template <typename T>
constexpr bool is_destructible_v = __is_destructible(T);


#endif

#ifdef STD2
Expand Down Expand Up @@ -167,6 +176,17 @@ using is_abstract = __details_is_abstract<T>;
template <typename T>
constexpr bool is_abstract_v = __is_abstract(T);

template <typename T>
struct __details_is_destructible {
static constexpr bool value = __is_destructible(T);
};

template <typename T>
using is_destructible = __details_is_destructible<T>;

template <typename T>
constexpr bool is_destructible_v = __is_destructible(T);

#endif


Expand Down Expand Up @@ -252,6 +272,15 @@ using is_abstract = __details_is_abstract<T>;
template <typename T>
constexpr bool is_abstract_v = is_abstract<T>::value;

template <typename T>
struct __details_is_destructible : bool_constant<__is_destructible(T)> {};

template <typename T>
using is_destructible = __details_is_destructible<T>;

template <typename T>
constexpr bool is_destructible_v = is_destructible<T>::value;

#endif
}

Expand Down Expand Up @@ -374,6 +403,18 @@ static_assert(std::is_abstract_v<int&>);
// expected-note@-1 {{because it is a reference type}} \
// expected-note@-1 {{because it is not a struct or class type}}

static_assert(std::is_destructible<int>::value);

static_assert(std::is_destructible<void>::value);
// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_destructible<void>::value'}} \
// expected-note@-1 {{'void' is not destructible}} \
// expected-note@-1 {{because it is a cv void type}}

static_assert(std::is_destructible_v<void>);
// expected-error@-1 {{static assertion failed due to requirement 'std::is_destructible_v<void>'}} \
// expected-note@-1 {{'void' is not destructible}} \
// expected-note@-1 {{because it is a cv void type}}


namespace test_namespace {
using namespace std;
Expand Down Expand Up @@ -473,6 +514,17 @@ namespace test_namespace {
// expected-note@-1 {{'int &' is not abstract}} \
// expected-note@-1 {{because it is a reference type}} \
// expected-note@-1 {{because it is not a struct or class type}}

static_assert(is_destructible<void>::value);
// expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_destructible<void>::value'}} \
// expected-note@-1 {{'void' is not destructible}} \
// expected-note@-1 {{because it is a cv void type}}

static_assert(is_destructible_v<void>);
// expected-error@-1 {{static assertion failed due to requirement 'is_destructible_v<void>'}} \
// expected-note@-1 {{'void' is not destructible}} \
// expected-note@-1 {{because it is a cv void type}}

}


Expand Down Expand Up @@ -518,6 +570,15 @@ concept C5 = std::is_aggregate_v<T>; // #concept10

template <C5 T> void g5(); // #cand10

template <typename T>
requires std::is_destructible<T>::value void f6(); // #cand11

template <typename T>
concept C6 = std::is_destructible_v<T>; // #concept11

template <C6 T> void g6(); // #cand12


void test() {
f<int&>();
// expected-error@-1 {{no matching function for call to 'f'}} \
Expand Down Expand Up @@ -589,6 +650,21 @@ void test() {
// expected-note@#concept10 {{because 'std::is_aggregate_v<void>' evaluated to false}} \
// expected-note@#concept10 {{'void' is not aggregate}} \
// expected-note@#concept10 {{because it is a cv void type}}

f6<void>();
// expected-error@-1 {{no matching function for call to 'f6'}} \
// expected-note@#cand11 {{candidate template ignored: constraints not satisfied [with T = void]}} \
// expected-note-re@#cand11 {{because '{{.*}}is_destructible<void>::value' evaluated to false}} \
// expected-note@#cand11 {{'void' is not destructible}} \
// expected-note@#cand11 {{because it is a cv void type}}

g6<void>();
// expected-error@-1 {{no matching function for call to 'g6'}} \
// expected-note@#cand12 {{candidate template ignored: constraints not satisfied [with T = void]}} \
// expected-note@#cand12 {{because 'void' does not satisfy 'C6'}} \
// expected-note@#concept11 {{because 'std::is_destructible_v<void>' evaluated to false}} \
// expected-note@#concept11 {{'void' is not destructible}} \
// expected-note@#concept11 {{because it is a cv void type}}
}
}

Expand Down
49 changes: 49 additions & 0 deletions clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,3 +1052,52 @@ static_assert(__is_abstract(U));
// expected-note@-1 {{because it is not a struct or class type}}

}
namespace destructible {

struct Incomplete; // expected-note {{forward declaration of 'destructible::Incomplete'}}
static_assert(__is_destructible(Incomplete));
// expected-error@-1 {{incomplete type 'Incomplete' used in type trait expression}}

static_assert(__is_destructible(void));
// expected-error@-1 {{static assertion failed due to requirement '__is_destructible(void)'}} \
// expected-note@-1 {{'void' is not destructible}} \
// expected-note@-1 {{because it is a cv void type}}

using F = void();
static_assert(__is_destructible(F));
// expected-error@-1 {{static assertion failed due to requirement '__is_destructible(void ())'}} \
// expected-note@-1 {{'void ()' is not destructible}} \
// expected-note@-1 {{because it is a function type}}

using Ref = int&;
static_assert(__is_destructible(Ref)); // no diagnostics (true)

struct DeletedDtor { // #d-DeletedDtor
~DeletedDtor() = delete;
};
static_assert(__is_destructible(DeletedDtor));
// expected-error@-1 {{static assertion failed due to requirement '__is_destructible(destructible::DeletedDtor)'}} \
// expected-note@-1 {{'destructible::DeletedDtor' is not destructible}} \
// expected-note@-1 {{because it has a deleted destructor}}

struct PrivateDtor { // #d-PrivateDtor
private:
~PrivateDtor(); // #d-PrivateDtor-dtor
};
static_assert(__is_destructible(PrivateDtor));
// expected-error@-1 {{static assertion failed due to requirement '__is_destructible(destructible::PrivateDtor)'}} \
// expected-note@-1 {{'destructible::PrivateDtor' is not destructible}} \
// expected-note@-1 {{because it has a private destructor}}

struct BaseInaccessible { // #d-BaseInacc
private:
~BaseInaccessible(); // #d-BaseInacc-dtor
};

struct DerivedFromInaccessible : BaseInaccessible {}; // #d-DerivedInacc
static_assert(__is_destructible(DerivedFromInaccessible));
// expected-error@-1 {{static assertion failed due to requirement '__is_destructible(destructible::DerivedFromInaccessible)'}} \
// expected-note@-1 {{'destructible::DerivedFromInaccessible' is not destructible}} \
// expected-note@-1 {{because it has a deleted destructor}}

}
36 changes: 36 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/FMF.h"
#include "llvm/MC/TargetRegistry.h"
Expand Down Expand Up @@ -2084,6 +2085,41 @@ unsigned GISelValueTracking::computeNumSignBits(Register R,
FirstAnswer = std::min(Src1NumSignBits, Src2NumSignBits) - 1;
break;
}
case TargetOpcode::G_MUL: {
Register Src1 = MI.getOperand(1).getReg();
Register Src2 = MI.getOperand(2).getReg();

KnownBits Known1 = getKnownBits(Src1, DemandedElts, Depth + 1);
KnownBits Known2 = getKnownBits(Src2, DemandedElts, Depth + 1);

if (Known1.isZero() || Known2.isZero())
return TyBits;

auto C1 = getIConstantVRegValWithLookThrough(Src1, MRI);
auto C2 = getIConstantVRegValWithLookThrough(Src2, MRI);

if (C1 && C2) {
APInt Val1 = C1->Value;
APInt Val2 = C2->Value;
APInt Product = Val1 * Val2;
return Product.getNumSignBits();
}
unsigned Src1NumSignBits =
computeNumSignBits(Src1, DemandedElts, Depth + 1);
if (Src1NumSignBits == 1) {
return 1;
}
unsigned Src2NumSignBits =
computeNumSignBits(Src2, DemandedElts, Depth + 1);
if (Src2NumSignBits == 1) {
return 1;
}

unsigned OutValidBits =
(TyBits - Src1NumSignBits + 1) + (TyBits - Src2NumSignBits + 1);
FirstAnswer = OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1;
break;
}
case TargetOpcode::G_FCMP:
case TargetOpcode::G_ICMP: {
bool IsFP = Opcode == TargetOpcode::G_FCMP;
Expand Down
Loading