Skip to content

Commit dc56a86

Browse files
[clang] Fix 7131569 in presence of incomplete types (#114095)
Incomplete types are not considered trivially copyable by clang but we don't want to warn about invalid argument for memcpy / memset in that case because we cannot prove they are not Trivially Copyable.
1 parent 5df84a7 commit dc56a86

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8900,7 +8900,12 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
89008900
<< Call->getCallee()->getSourceRange());
89018901
else if (const auto *RT = PointeeTy->getAs<RecordType>()) {
89028902

8903-
bool IsTriviallyCopyableCXXRecord =
8903+
// FIXME: Do not consider incomplete types even though they may be
8904+
// completed later. GCC does not diagnose such code, but we may want to
8905+
// consider diagnosing it in the future, perhaps under a different, but
8906+
// related, diagnostic group.
8907+
bool MayBeTriviallyCopyableCXXRecord =
8908+
RT->isIncompleteType() ||
89048909
RT->desugar().isTriviallyCopyableType(Context);
89058910

89068911
if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
@@ -8910,7 +8915,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
89108915
<< ArgIdx << FnName << PointeeTy << 0);
89118916
SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this);
89128917
} else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
8913-
!IsTriviallyCopyableCXXRecord && ArgIdx == 0) {
8918+
!MayBeTriviallyCopyableCXXRecord && ArgIdx == 0) {
89148919
// FIXME: Limiting this warning to dest argument until we decide
89158920
// whether it's valid for source argument too.
89168921
DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
@@ -8923,7 +8928,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
89238928
<< ArgIdx << FnName << PointeeTy << 1);
89248929
SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this);
89258930
} else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
8926-
!IsTriviallyCopyableCXXRecord && ArgIdx == 0) {
8931+
!MayBeTriviallyCopyableCXXRecord && ArgIdx == 0) {
89278932
// FIXME: Limiting this warning to dest argument until we decide
89288933
// whether it's valid for source argument too.
89298934
DiagRuntimeBehavior(Dest->getExprLoc(), Dest,

clang/test/SemaCXX/constexpr-string.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,8 +670,6 @@ namespace MemcpyEtc {
670670
constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}}
671671
struct Incomplete;
672672
extern Incomplete x, y;
673-
// expected-warning@+2 {{first argument in call to '__builtin_memcpy' is a pointer to non-trivially copyable type 'Incomplete'}}
674-
// expected-note@+1 {{explicitly cast the pointer to silence this warning}}
675673
__builtin_memcpy(&x, &x, 4);
676674
// expected-note@-1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
677675
return true;

clang/test/SemaCXX/warn-memaccess.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
77

88
class TriviallyCopyable {};
99
class NonTriviallyCopyable { NonTriviallyCopyable(const NonTriviallyCopyable&);};
10+
struct Incomplete;
1011

1112
void test_bzero(TriviallyCopyable* tc,
12-
NonTriviallyCopyable *ntc) {
13+
NonTriviallyCopyable *ntc,
14+
Incomplete* i) {
1315
// OK
1416
bzero(tc, sizeof(*tc));
1517

18+
// OK
19+
bzero(i, 10);
20+
1621
// expected-warning@+2{{first argument in call to 'bzero' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}}
1722
// expected-note@+1{{explicitly cast the pointer to silence this warning}}
1823
bzero(ntc, sizeof(*ntc));
@@ -22,10 +27,14 @@ void test_bzero(TriviallyCopyable* tc,
2227
}
2328

2429
void test_memset(TriviallyCopyable* tc,
25-
NonTriviallyCopyable *ntc) {
30+
NonTriviallyCopyable *ntc,
31+
Incomplete* i) {
2632
// OK
2733
memset(tc, 0, sizeof(*tc));
2834

35+
// OK
36+
memset(i, 0, 10);
37+
2938
// expected-warning@+2{{first argument in call to 'memset' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}}
3039
// expected-note@+1{{explicitly cast the pointer to silence this warning}}
3140
memset(ntc, 0, sizeof(*ntc));
@@ -36,10 +45,14 @@ void test_memset(TriviallyCopyable* tc,
3645

3746

3847
void test_memcpy(TriviallyCopyable* tc0, TriviallyCopyable* tc1,
39-
NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1) {
48+
NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1,
49+
Incomplete *i0, Incomplete *i1) {
4050
// OK
4151
memcpy(tc0, tc1, sizeof(*tc0));
4252

53+
// OK
54+
memcpy(i0, i1, 10);
55+
4356
// expected-warning@+2{{first argument in call to 'memcpy' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}}
4457
// expected-note@+1{{explicitly cast the pointer to silence this warning}}
4558
memcpy(ntc0, ntc1, sizeof(*ntc0));
@@ -52,10 +65,14 @@ void test_memcpy(TriviallyCopyable* tc0, TriviallyCopyable* tc1,
5265
}
5366

5467
void test_memmove(TriviallyCopyable* tc0, TriviallyCopyable* tc1,
55-
NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1) {
68+
NonTriviallyCopyable *ntc0, NonTriviallyCopyable *ntc1,
69+
Incomplete *i0, Incomplete *i1) {
5670
// OK
5771
memmove(tc0, tc1, sizeof(*tc0));
5872

73+
// OK
74+
memmove(i0, i1, 10);
75+
5976
// expected-warning@+2{{first argument in call to 'memmove' is a pointer to non-trivially copyable type 'NonTriviallyCopyable'}}
6077
// expected-note@+1{{explicitly cast the pointer to silence this warning}}
6178
memmove(ntc0, ntc1, sizeof(*ntc0));

0 commit comments

Comments
 (0)