Skip to content

Commit efcf192

Browse files
authored
Changed Checks from TriviallyCopyable to TriviallyCopyConstructible (#77194)
**Overview:** Fix a bug where Clang's range-loop-analysis incorrectly checks for trivial copyability instead of trivial copy constructibility, leading to erroneous warnings. Fixes #47355
1 parent 7fc7ef1 commit efcf192

File tree

7 files changed

+73
-10
lines changed

7 files changed

+73
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,9 @@ Bug Fixes to AST Handling
884884
- Fixed a bug where RecursiveASTVisitor fails to visit the
885885
initializer of a bitfield.
886886
`Issue 64916 <https://github.com/llvm/llvm-project/issues/64916>`_
887+
- Fixed a bug where range-loop-analysis checks for trivial copyability,
888+
rather than trivial copy-constructibility
889+
`Issue 47355 <https://github.com/llvm/llvm-project/issues/47355>`_
887890
- Fixed a bug where Template Instantiation failed to handle Lambda Expressions
888891
with certain types of Attributes.
889892
(`#76521 <https://github.com/llvm/llvm-project/issues/76521>`_)

clang/include/clang/AST/DeclCXX.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,9 @@ class CXXRecordDecl : public RecordDecl {
14251425
/// (C++11 [class]p6).
14261426
bool isTriviallyCopyable() const;
14271427

1428+
/// Determine whether this class is considered trivially copyable per
1429+
bool isTriviallyCopyConstructible() const;
1430+
14281431
/// Determine whether this class is considered trivial.
14291432
///
14301433
/// C++11 [class]p6:

clang/include/clang/AST/Type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,9 @@ class QualType {
917917
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
918918
bool isTriviallyCopyableType(const ASTContext &Context) const;
919919

920+
/// Return true if this is a trivially copyable type
921+
bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;
922+
920923
/// Return true if this is a trivially relocatable type.
921924
bool isTriviallyRelocatableType(const ASTContext &Context) const;
922925

clang/lib/AST/DeclCXX.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,19 @@ bool CXXRecordDecl::isTriviallyCopyable() const {
587587
return true;
588588
}
589589

590+
bool CXXRecordDecl::isTriviallyCopyConstructible() const {
591+
592+
// A trivially copy constructible class is a class that:
593+
// -- has no non-trivial copy constructors,
594+
if (hasNonTrivialCopyConstructor())
595+
return false;
596+
// -- has a trivial destructor.
597+
if (!hasTrivialDestructor())
598+
return false;
599+
600+
return true;
601+
}
602+
590603
void CXXRecordDecl::markedVirtualFunctionPure() {
591604
// C++ [class.abstract]p2:
592605
// A class is abstract if it has at least one pure virtual function.

clang/lib/AST/Type.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,19 +2604,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
26042604
return false;
26052605
}
26062606

2607-
bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
2608-
if ((*this)->isArrayType())
2609-
return Context.getBaseElementType(*this).isTriviallyCopyableType(Context);
2607+
static bool isTriviallyCopyableTypeImpl(const QualType &type,
2608+
const ASTContext &Context,
2609+
bool IsCopyConstructible) {
2610+
if (type->isArrayType())
2611+
return isTriviallyCopyableTypeImpl(Context.getBaseElementType(type),
2612+
Context, IsCopyConstructible);
26102613

2611-
if (hasNonTrivialObjCLifetime())
2614+
if (type.hasNonTrivialObjCLifetime())
26122615
return false;
26132616

26142617
// C++11 [basic.types]p9 - See Core 2094
26152618
// Scalar types, trivially copyable class types, arrays of such types, and
26162619
// cv-qualified versions of these types are collectively
2617-
// called trivially copyable types.
2620+
// called trivially copy constructible types.
26182621

2619-
QualType CanonicalType = getCanonicalType();
2622+
QualType CanonicalType = type.getCanonicalType();
26202623
if (CanonicalType->isDependentType())
26212624
return false;
26222625

@@ -2634,16 +2637,29 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
26342637

26352638
if (const auto *RT = CanonicalType->getAs<RecordType>()) {
26362639
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
2637-
if (!ClassDecl->isTriviallyCopyable()) return false;
2640+
if (IsCopyConstructible) {
2641+
return ClassDecl->isTriviallyCopyConstructible();
2642+
} else {
2643+
return ClassDecl->isTriviallyCopyable();
2644+
}
26382645
}
2639-
26402646
return true;
26412647
}
2642-
26432648
// No other types can match.
26442649
return false;
26452650
}
26462651

2652+
bool QualType::isTriviallyCopyableType(const ASTContext &Context) const {
2653+
return isTriviallyCopyableTypeImpl(*this, Context,
2654+
/*IsCopyConstructible=*/false);
2655+
}
2656+
2657+
bool QualType::isTriviallyCopyConstructibleType(
2658+
const ASTContext &Context) const {
2659+
return isTriviallyCopyableTypeImpl(*this, Context,
2660+
/*IsCopyConstructible=*/true);
2661+
}
2662+
26472663
bool QualType::isTriviallyRelocatableType(const ASTContext &Context) const {
26482664
QualType BaseElementType = Context.getBaseElementType(*this);
26492665

clang/lib/Sema/SemaStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3200,7 +3200,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
32003200
// (The function `getTypeSize` returns the size in bits.)
32013201
ASTContext &Ctx = SemaRef.Context;
32023202
if (Ctx.getTypeSize(VariableType) <= 64 * 8 &&
3203-
(VariableType.isTriviallyCopyableType(Ctx) ||
3203+
(VariableType.isTriviallyCopyConstructibleType(Ctx) ||
32043204
hasTrivialABIAttr(VariableType)))
32053205
return;
32063206

clang/test/SemaCXX/warn-range-loop-analysis-trivially-copyable.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ void test_TriviallyCopyable_64_bytes() {
3333
for (const auto r : records)
3434
(void)r;
3535
}
36+
void test_TriviallyCopyConstructible_64_bytes() {
37+
struct Record {
38+
char a[64];
39+
Record& operator=(Record const& other){return *this;};
40+
41+
};
42+
43+
Record records[8];
44+
for (const auto r : records)
45+
(void)r;
46+
}
3647

3748
void test_TriviallyCopyable_65_bytes() {
3849
struct Record {
@@ -47,6 +58,19 @@ void test_TriviallyCopyable_65_bytes() {
4758
(void)r;
4859
}
4960

61+
void test_TriviallyCopyConstructible_65_bytes() {
62+
struct Record {
63+
char a[65];
64+
Record& operator=(Record const& other){return *this;};
65+
66+
};
67+
// expected-warning@+3 {{loop variable 'r' creates a copy from type 'const Record'}}
68+
// expected-note@+2 {{use reference type 'const Record &' to prevent copying}}
69+
Record records[8];
70+
for (const auto r : records)
71+
(void)r;
72+
}
73+
5074
void test_NonTriviallyCopyable() {
5175
struct Record {
5276
Record() {}
@@ -87,3 +111,4 @@ void test_TrivialABI_65_bytes() {
87111
for (const auto r : records)
88112
(void)r;
89113
}
114+

0 commit comments

Comments
 (0)