-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[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 4 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" | ||||||||||||||||
|
|
@@ -1922,6 +1924,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) | ||||||||||||||||
|
Collaborator
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
Contributor
Author
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
Collaborator
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
Contributor
Author
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?
Collaborator
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.
Contributor
Author
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)
Contributor
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); | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -2083,6 +2086,88 @@ 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())) { | ||||||||||||||||
|
Collaborator
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?
Contributor
Author
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(); | ||||||||||||||||
| } | ||||||||||||||||
| if (D->hasDeletedDestructor()) | ||||||||||||||||
| SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) | ||||||||||||||||
| << diag::TraitNotSatisfiedReason::DeletedDtr << 0 | ||||||||||||||||
| << D->getDestructor()->getSourceRange(); | ||||||||||||||||
|
|
||||||||||||||||
| for (const CXXMethodDecl *Method : D->methods()) { | ||||||||||||||||
| if (Method->isIneligibleOrNotSelected() || Method->isTrivial() || | ||||||||||||||||
|
||||||||||||||||
| !Method->isUserProvided()) { | ||||||||||||||||
| continue; | ||||||||||||||||
| } | ||||||||||||||||
| auto SpecialMemberKind = | ||||||||||||||||
| SemaRef.getDefaultedFunctionKind(Method).asSpecialMember(); | ||||||||||||||||
| switch (SpecialMemberKind) { | ||||||||||||||||
| case CXXSpecialMemberKind::CopyConstructor: | ||||||||||||||||
|
Collaborator
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?
Contributor
Author
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; | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
||||||||||||||||
| default: { | |
| 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.
Fixed
Outdated
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.
Can you move that to the previous place where we talked about the destructor?
We should say either "has a deleted destructor" or "has a non-trivial destructor" (but not both)
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.
Oh, fixed it, decided to write "has a deleted destructor". Is it good now?
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -144,3 +144,54 @@ static_assert(__builtin_is_cpp_trivially_relocatable(U2)); | |
| // expected-note@#tr-U2 {{'U2' defined here}} | ||
|
|
||
| } | ||
|
|
||
| namespace trivially_copyable { | ||
| struct B { | ||
| virtual ~B(); | ||
| }; | ||
| struct S : virtual B { // #tc-S | ||
| S(); | ||
| int & a; | ||
| const int ci; | ||
| B & b; | ||
| B c; | ||
| ~S(); | ||
| }; | ||
| static_assert(__is_trivially_copyable(S)); | ||
| // expected-error@-1 {{static assertion failed due to requirement '__is_trivially_copyable(trivially_copyable::S)'}} \ | ||
| // expected-note@-1 {{'S' is not trivially copyable}} \ | ||
| // expected-note@-1 {{because it has a virtual base 'B'}} \ | ||
| // expected-note@-1 {{because it has a non-trivially-copyable base 'B'}} \ | ||
|
Collaborator
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. We should test a case in which there are multiple non-trvial-copyable bases.
Contributor
Author
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 some tests for this case
Collaborator
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 see the other test case you added but I don't see the test case for multiple base classes. I am guessing maybe you missed a commit.
Contributor
Author
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. It seems that I have added a tests with multiple base classes (structs S5, S6). Or do you need a test with three or more? Or what do you mean by "multiple base classes"?
Contributor
Author
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. It seems that I've figured it out. I added one more test. |
||
| // expected-note@-1 {{because it has a non-trivially-copyable member 'c' of type 'B'}} \ | ||
| // expected-note@-1 {{because it has a non-trivially-copyable member 'b' of type 'B &'}} \ | ||
| // expected-note@-1 {{because it has a non-trivially-copyable member 'a' of type 'int &'}} \ | ||
| // expected-note@-1 {{because it has a user-provided destructor}} | ||
| // expected-note@#tc-S {{'S' defined here}} | ||
|
|
||
| struct S2 { // #tc-S2 | ||
| S2(S2&&); | ||
| S2& operator=(const S2&); | ||
| }; | ||
| static_assert(__is_trivially_copyable(S2)); | ||
| // expected-error@-1 {{static assertion failed due to requirement '__is_trivially_copyable(trivially_copyable::S2)'}} \ | ||
| // expected-note@-1 {{'S2' is not trivially copyable}} \ | ||
| // expected-note@-1 {{because it has a user provided move constructor}} \ | ||
| // expected-note@-1 {{because it has a user provided copy assignment operator}} \ | ||
| // expected-note@#tc-S2 {{'S2' defined here}} | ||
|
|
||
| struct S3 { | ||
| ~S3() = delete; | ||
| }; | ||
| static_assert(__is_trivially_copyable(S3)); | ||
|
|
||
| struct S4 { // #tc-S4 | ||
| ~S4(); | ||
| B b; | ||
| }; | ||
| static_assert(__is_trivially_copyable(S4)); | ||
| // expected-error@-1 {{static assertion failed due to requirement '__is_trivially_copyable(trivially_copyable::S4)'}} \ | ||
| // expected-note@-1 {{'S4' is not trivially copyable}} \ | ||
| // expected-note@-1 {{because it has a non-trivially-copyable member 'b' of type 'B'}} \ | ||
| // expected-note@-1 {{because it has a user-provided destructor}} \ | ||
| // expected-note@#tc-S4 {{'S4' defined here}} | ||
| } | ||
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-relocatabletook onlyNRwhereas this is takingNTC. That said, I VASTLY prefer theTbe present. Not in the scope here of course, but a followup tochange thoseNRtoNTRperhaps 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