-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Added explanation why is_trivially_copyable
evaluated to false.
#142341
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
Changes from all commits
2e423a7
8edd53d
65ca243
9880d4f
2401565
94bec75
8636714
437992d
7f999b9
1836846
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,10 @@ | |
//===----------------------------------------------------------------------===// | ||
|
||
#include "clang/AST/DeclCXX.h" | ||
#include "clang/AST/Type.h" | ||
#include "clang/Basic/DiagnosticParse.h" | ||
#include "clang/Basic/DiagnosticSema.h" | ||
#include "clang/Basic/TypeTraits.h" | ||
#include "clang/Sema/EnterExpressionEvaluationContext.h" | ||
#include "clang/Sema/Initialization.h" | ||
#include "clang/Sema/Lookup.h" | ||
|
@@ -1938,6 +1940,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) { | |
return llvm::StringSwitch<std::optional<TypeTrait>>(Name) | ||
.Case("is_trivially_relocatable", | ||
TypeTrait::UTT_IsCppTriviallyRelocatable) | ||
.Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 isnt the number, but at a certain number of entries here, we're going to want to tablegen/.def file this. Perhaps in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if I did it right, but I couldn't figure out how from TYPE_TRAIT_1 could get a name without the "__" prefix. So I made a TYPE_TRAIT_DIAG for this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, no, I was suggesting adding a new field to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should I revert changes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I'd suggest going back to the original, unless you want to do all the work for updating the TYPE_TRAIT_N/TYPE_TRAIT_1 (which I'm not requiring here at all!). Just something to think about for a future direction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, thanks) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @erichkeane yeah, maybe we should move the whole type traits thing to a tablegen file at some point... but it seems involved |
||
.Default(std::nullopt); | ||
} | ||
|
||
|
@@ -2013,15 +2016,15 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, | |
<< B.getSourceRange(); | ||
if (!SemaRef.IsCXXTriviallyRelocatableType(B.getType())) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::NRBase << B.getType() | ||
<< diag::TraitNotSatisfiedReason::NTRBase << B.getType() | ||
<< B.getSourceRange(); | ||
} | ||
for (const FieldDecl *Field : D->fields()) { | ||
if (!Field->getType()->isReferenceType() && | ||
!SemaRef.IsCXXTriviallyRelocatableType(Field->getType())) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::NRField << Field << Field->getType() | ||
<< Field->getSourceRange(); | ||
<< diag::TraitNotSatisfiedReason::NTRField << Field | ||
<< Field->getType() << Field->getSourceRange(); | ||
} | ||
if (D->hasDeletedDestructor()) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
|
@@ -2099,6 +2102,82 @@ static void DiagnoseNonTriviallyRelocatableReason(Sema &SemaRef, | |
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; | ||
} | ||
|
||
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, | ||
SourceLocation Loc, | ||
const CXXRecordDecl *D) { | ||
for (const CXXBaseSpecifier &B : D->bases()) { | ||
assert(B.getType()->getAsCXXRecordDecl() && "invalid base?"); | ||
if (B.isVirtual()) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::VBase << B.getType() | ||
<< B.getSourceRange(); | ||
if (!B.getType().isTriviallyCopyableType(D->getASTContext())) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this if statement covered in the tests below? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added test for it |
||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::NTCBase << B.getType() | ||
<< B.getSourceRange(); | ||
} | ||
} | ||
for (const FieldDecl *Field : D->fields()) { | ||
if (!Field->getType().isTriviallyCopyableType(Field->getASTContext())) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::NTCField << Field | ||
<< Field->getType() << Field->getSourceRange(); | ||
} | ||
CXXDestructorDecl *Dtr = D->getDestructor(); | ||
if (D->hasDeletedDestructor() || (Dtr && !Dtr->isTrivial())) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::DeletedDtr | ||
<< !D->hasDeletedDestructor() << D->getDestructor()->getSourceRange(); | ||
|
||
for (const CXXMethodDecl *Method : D->methods()) { | ||
if (Method->isTrivial() || !Method->isUserProvided()) { | ||
continue; | ||
} | ||
auto SpecialMemberKind = | ||
SemaRef.getDefaultedFunctionKind(Method).asSpecialMember(); | ||
switch (SpecialMemberKind) { | ||
case CXXSpecialMemberKind::CopyConstructor: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If every single case label covered in the tests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added tests for every single case |
||
case CXXSpecialMemberKind::MoveConstructor: | ||
case CXXSpecialMemberKind::CopyAssignment: | ||
case CXXSpecialMemberKind::MoveAssignment: { | ||
bool IsAssignment = | ||
SpecialMemberKind == CXXSpecialMemberKind::CopyAssignment || | ||
SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment; | ||
bool IsMove = | ||
SpecialMemberKind == CXXSpecialMemberKind::MoveConstructor || | ||
SpecialMemberKind == CXXSpecialMemberKind::MoveAssignment; | ||
|
||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< (IsAssignment ? diag::TraitNotSatisfiedReason::UserProvidedAssign | ||
: diag::TraitNotSatisfiedReason::UserProvidedCtr) | ||
<< IsMove << Method->getSourceRange(); | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
|
||
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, | ||
SourceLocation Loc, QualType T) { | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait) | ||
<< T << diag::TraitName::TriviallyCopyable; | ||
|
||
if (T->isReferenceType()) | ||
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||
<< diag::TraitNotSatisfiedReason::Ref; | ||
|
||
const CXXRecordDecl *D = T->getAsCXXRecordDecl(); | ||
if (!D || D->isInvalidDecl()) | ||
return; | ||
|
||
if (D->hasDefinition()) | ||
DiagnoseNonTriviallyCopyableReason(SemaRef, Loc, D); | ||
|
||
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; | ||
} | ||
|
||
void Sema::DiagnoseTypeTraitDetails(const Expr *E) { | ||
E = E->IgnoreParenImpCasts(); | ||
if (E->containsErrors()) | ||
|
@@ -2113,6 +2192,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) { | |
case UTT_IsCppTriviallyRelocatable: | ||
DiagnoseNonTriviallyRelocatableReason(*this, E->getBeginLoc(), Args[0]); | ||
break; | ||
case UTT_IsTriviallyCopyable: | ||
DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]); | ||
break; | ||
default: | ||
break; | ||
} | ||
|
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.
The enum names here are inconsistent...
non-trivially-relocatable
took onlyNR
whereas this is takingNTC
. That said, I VASTLY prefer theT
be present. Not in the scope here of course, but a followup tochange thoseNR
toNTR
perhaps is valuable.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.
Changed NR to NTR