forked from OSchip/llvm-project
[Builtins] Treat `bcmp` as a builtin.
Summary: This makes it consistent with `memcmp` and `__builtin_bcmp`. Also see the discussion in https://reviews.llvm.org/D56593. Reviewers: jyknight Subscribers: kristina, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D58120 llvm-svn: 354023
This commit is contained in:
parent
5d9b8eed85
commit
8c3343dfd5
|
@ -448,7 +448,7 @@ BUILTIN(__builtin_va_end, "vA", "n")
|
|||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||
BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
|
||||
BUILTIN(__builtin_bcmp, "iv*v*z", "Fn")
|
||||
BUILTIN(__builtin_bcmp, "ivC*vC*z", "Fn")
|
||||
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
|
||||
BUILTIN(__builtin_bzero, "vv*z", "nF")
|
||||
BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:")
|
||||
|
@ -953,6 +953,7 @@ LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_GNU_LANGUAGES)
|
|||
LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES)
|
||||
LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_GNU_LANGUAGES)
|
||||
LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_GNU_LANGUAGES)
|
||||
LIBBUILTIN(bcmp, "ivC*vC*z", "f", "strings.h", ALL_GNU_LANGUAGES)
|
||||
// In some systems str[n]casejmp is a macro that expands to _str[n]icmp.
|
||||
// We undefine then here to avoid wrong name.
|
||||
#undef strcasecmp
|
||||
|
|
|
@ -3672,6 +3672,10 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
|
|||
case Builtin::BImemcmp:
|
||||
return Builtin::BImemcmp;
|
||||
|
||||
case Builtin::BI__builtin_bcmp:
|
||||
case Builtin::BIbcmp:
|
||||
return Builtin::BIbcmp;
|
||||
|
||||
case Builtin::BI__builtin_strncpy:
|
||||
case Builtin::BI__builtin___strncpy_chk:
|
||||
case Builtin::BIstrncpy:
|
||||
|
@ -3712,6 +3716,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
|
|||
return Builtin::BImemmove;
|
||||
else if (FnInfo->isStr("memcmp"))
|
||||
return Builtin::BImemcmp;
|
||||
else if (FnInfo->isStr("bcmp"))
|
||||
return Builtin::BIbcmp;
|
||||
else if (FnInfo->isStr("strncpy"))
|
||||
return Builtin::BIstrncpy;
|
||||
else if (FnInfo->isStr("strncmp"))
|
||||
|
|
|
@ -8426,6 +8426,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
case Builtin::BIstrncmp:
|
||||
case Builtin::BIwcsncmp:
|
||||
case Builtin::BImemcmp:
|
||||
case Builtin::BIbcmp:
|
||||
case Builtin::BIwmemcmp:
|
||||
// A call to strlen is not a constant expression.
|
||||
if (Info.getLangOpts().CPlusPlus11)
|
||||
|
@ -8440,6 +8441,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
case Builtin::BI__builtin_strncmp:
|
||||
case Builtin::BI__builtin_wcsncmp:
|
||||
case Builtin::BI__builtin_memcmp:
|
||||
case Builtin::BI__builtin_bcmp:
|
||||
case Builtin::BI__builtin_wmemcmp: {
|
||||
LValue String1, String2;
|
||||
if (!EvaluatePointer(E->getArg(0), String1, Info) ||
|
||||
|
@ -8470,7 +8472,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
QualType CharTy2 = String2.Designator.getType(Info.Ctx);
|
||||
|
||||
bool IsRawByte = BuiltinOp == Builtin::BImemcmp ||
|
||||
BuiltinOp == Builtin::BI__builtin_memcmp;
|
||||
BuiltinOp == Builtin::BIbcmp ||
|
||||
BuiltinOp == Builtin::BI__builtin_memcmp ||
|
||||
BuiltinOp == Builtin::BI__builtin_bcmp;
|
||||
|
||||
assert(IsRawByte ||
|
||||
(Info.Ctx.hasSameUnqualifiedType(
|
||||
|
@ -8538,10 +8542,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
return Success(0, E);
|
||||
}
|
||||
|
||||
bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
|
||||
BuiltinOp != Builtin::BIwmemcmp &&
|
||||
BuiltinOp != Builtin::BI__builtin_memcmp &&
|
||||
BuiltinOp != Builtin::BI__builtin_wmemcmp);
|
||||
bool StopAtNull =
|
||||
(BuiltinOp != Builtin::BImemcmp && BuiltinOp != Builtin::BIbcmp &&
|
||||
BuiltinOp != Builtin::BIwmemcmp &&
|
||||
BuiltinOp != Builtin::BI__builtin_memcmp &&
|
||||
BuiltinOp != Builtin::BI__builtin_bcmp &&
|
||||
BuiltinOp != Builtin::BI__builtin_wmemcmp);
|
||||
bool IsWide = BuiltinOp == Builtin::BIwcscmp ||
|
||||
BuiltinOp == Builtin::BIwcsncmp ||
|
||||
BuiltinOp == Builtin::BIwmemcmp ||
|
||||
|
|
|
@ -9174,23 +9174,23 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
|
|||
getContainedDynamicClass(PointeeTy, IsContained)) {
|
||||
|
||||
unsigned OperationType = 0;
|
||||
const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
|
||||
// "overwritten" if we're warning about the destination for any call
|
||||
// but memcmp; otherwise a verb appropriate to the call.
|
||||
if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
|
||||
if (ArgIdx != 0 || IsCmp) {
|
||||
if (BId == Builtin::BImemcpy)
|
||||
OperationType = 1;
|
||||
else if(BId == Builtin::BImemmove)
|
||||
OperationType = 2;
|
||||
else if (BId == Builtin::BImemcmp)
|
||||
else if (IsCmp)
|
||||
OperationType = 3;
|
||||
}
|
||||
|
||||
DiagRuntimeBehavior(
|
||||
Dest->getExprLoc(), Dest,
|
||||
PDiag(diag::warn_dyn_class_memaccess)
|
||||
<< (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
|
||||
<< FnName << IsContained << ContainedRD << OperationType
|
||||
<< Call->getCallee()->getSourceRange());
|
||||
DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
|
||||
PDiag(diag::warn_dyn_class_memaccess)
|
||||
<< (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName
|
||||
<< IsContained << ContainedRD << OperationType
|
||||
<< Call->getCallee()->getSourceRange());
|
||||
} else if (PointeeTy.hasNonTrivialObjCLifetime() &&
|
||||
BId != Builtin::BImemset)
|
||||
DiagRuntimeBehavior(
|
||||
|
|
|
@ -361,8 +361,7 @@ void memmove2 () {
|
|||
#ifdef VARIANT
|
||||
|
||||
#define bcmp BUILTIN(bcmp)
|
||||
// __builtin_bcmp is not defined with const in Builtins.def.
|
||||
int bcmp(/*const*/ void *s1, /*const*/ void *s2, size_t n);
|
||||
int bcmp(const void *s1, const void *s2, size_t n);
|
||||
#define memcmp bcmp
|
||||
//
|
||||
#else /* VARIANT */
|
||||
|
|
|
@ -41,7 +41,7 @@ void test_float_condition() {
|
|||
}
|
||||
|
||||
// Obsolete function bcmp
|
||||
int bcmp(void *, void *, size_t);
|
||||
int bcmp(const void *, const void *, size_t);
|
||||
|
||||
int test_bcmp(void *a, void *b, size_t n) {
|
||||
return bcmp(a, b, n); // expected-warning{{The bcmp() function is obsoleted by memcmp()}}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
|
||||
// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
|
||||
// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
|
||||
// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
|
||||
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
|
||||
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
|
||||
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
|
||||
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
|
||||
|
||||
|
@ -15,6 +17,10 @@ extern "C" {
|
|||
extern int strncmp(const char *s1, const char *s2, size_t n);
|
||||
extern int memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
||||
#ifdef GNUMODE
|
||||
extern int bcmp(const void *s1, const void *s2, size_t n);
|
||||
#endif
|
||||
|
||||
extern char *strchr(const char *s, int c);
|
||||
extern void *memchr(const void *s, int c, size_t n);
|
||||
|
||||
|
@ -101,12 +107,28 @@ namespace StrcmpEtc {
|
|||
static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1);
|
||||
static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0);
|
||||
|
||||
static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
|
||||
static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
|
||||
static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
|
||||
static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
|
||||
static_assert(__builtin_bcmp(0, 0, 0) == 0);
|
||||
static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
|
||||
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
|
||||
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
|
||||
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
|
||||
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
|
||||
|
||||
extern struct Incomplete incomplete;
|
||||
static_assert(__builtin_memcmp(&incomplete, "", 0u) == 0);
|
||||
static_assert(__builtin_memcmp("", &incomplete, 0u) == 0);
|
||||
static_assert(__builtin_memcmp(&incomplete, "", 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
|
||||
static_assert(__builtin_memcmp("", &incomplete, 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
|
||||
|
||||
static_assert(__builtin_bcmp(&incomplete, "", 0u) == 0);
|
||||
static_assert(__builtin_bcmp("", &incomplete, 0u) == 0);
|
||||
static_assert(__builtin_bcmp(&incomplete, "", 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
|
||||
static_assert(__builtin_bcmp("", &incomplete, 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
|
||||
|
||||
constexpr unsigned char ku00fe00[] = {0x00, 0xfe, 0x00};
|
||||
constexpr unsigned char ku00feff[] = {0x00, 0xfe, 0xff};
|
||||
constexpr signed char ks00fe00[] = {0, -2, 0};
|
||||
|
@ -121,11 +143,24 @@ namespace StrcmpEtc {
|
|||
static_assert(__builtin_memcmp(ks00feff, ks00fe00, 99) == 1);
|
||||
static_assert(__builtin_memcmp(ks00fe00, ks00feff, 99) == -1);
|
||||
|
||||
static_assert(__builtin_bcmp(ku00feff, ks00fe00, 2) == 0);
|
||||
static_assert(__builtin_bcmp(ku00feff, ks00fe00, 99) != 0);
|
||||
static_assert(__builtin_bcmp(ku00fe00, ks00feff, 99) != 0);
|
||||
static_assert(__builtin_bcmp(ks00feff, ku00fe00, 2) == 0);
|
||||
static_assert(__builtin_bcmp(ks00feff, ku00fe00, 99) != 0);
|
||||
static_assert(__builtin_bcmp(ks00fe00, ku00feff, 99) != 0);
|
||||
static_assert(__builtin_bcmp(ks00fe00, ks00feff, 2) == 0);
|
||||
static_assert(__builtin_bcmp(ks00feff, ks00fe00, 99) != 0);
|
||||
static_assert(__builtin_bcmp(ks00fe00, ks00feff, 99) != 0);
|
||||
|
||||
struct Bool3Tuple { bool bb[3]; };
|
||||
constexpr Bool3Tuple kb000100 = {{false, true, false}};
|
||||
static_assert(sizeof(bool) != 1u || __builtin_memcmp(ks00fe00, kb000100.bb, 1) == 0);
|
||||
static_assert(sizeof(bool) != 1u || __builtin_memcmp(ks00fe00, kb000100.bb, 2) == 1);
|
||||
|
||||
static_assert(sizeof(bool) != 1u || __builtin_bcmp(ks00fe00, kb000100.bb, 1) == 0);
|
||||
static_assert(sizeof(bool) != 1u || __builtin_bcmp(ks00fe00, kb000100.bb, 2) != 0);
|
||||
|
||||
constexpr long ksl[] = {0, -1};
|
||||
constexpr unsigned int kui[] = {0, 0u - 1};
|
||||
constexpr unsigned long long kull[] = {0, 0ull - 1};
|
||||
|
@ -148,9 +183,23 @@ namespace StrcmpEtc {
|
|||
static_assert(__builtin_memcmp(ksl + 1, kuSizeofLong() + 1, sizeof(long) + 0) == 0);
|
||||
static_assert(__builtin_memcmp(ksl + 1, kuSizeofLong() + 1, sizeof(long) + 1) == 42); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
|
||||
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), sizeof(long) - 1) == 0);
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), sizeof(long) + 0) == 0);
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), sizeof(long) + 1) == 0);
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), 2*sizeof(long) - 1) == 0);
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), 2*sizeof(long) + 0) == 0);
|
||||
static_assert(__builtin_bcmp(ksl, kuSizeofLong(), 2*sizeof(long) + 1) == 42); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
|
||||
static_assert(__builtin_bcmp(ksl + 1, kuSizeofLong() + 1, sizeof(long) - 1) == 0);
|
||||
static_assert(__builtin_bcmp(ksl + 1, kuSizeofLong() + 1, sizeof(long) + 0) == 0);
|
||||
static_assert(__builtin_bcmp(ksl + 1, kuSizeofLong() + 1, sizeof(long) + 1) == 42); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
|
||||
|
||||
constexpr int a = strcmp("hello", "world"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strcmp' cannot be used in a constant expression}}
|
||||
constexpr int b = strncmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strncmp' cannot be used in a constant expression}}
|
||||
constexpr int c = memcmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'memcmp' cannot be used in a constant expression}}
|
||||
|
||||
#ifdef GNUMODE
|
||||
constexpr int d = bcmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'bcmp' cannot be used in a constant expression}}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace MultibyteElementTests {
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
extern "C" void *memset(void *, int, unsigned);
|
||||
extern "C" void *memmove(void *s1, const void *s2, unsigned n);
|
||||
extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
|
||||
extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
|
||||
extern "C" int memcmp(void *s1, const void *s2, unsigned n);
|
||||
extern "C" int bcmp(void *s1, const void *s2, unsigned n);
|
||||
|
||||
|
||||
// Redeclare without the extern "C" to test that we still figure out that this
|
||||
|
@ -59,6 +60,12 @@ void test_warn() {
|
|||
memcmp(0, &x1, sizeof x1); // \
|
||||
// expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
|
||||
// expected-note {{explicitly cast the pointer to silence this warning}}
|
||||
bcmp(&x1, 0, sizeof x1); // \
|
||||
// expected-warning{{first operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
|
||||
// expected-note {{explicitly cast the pointer to silence this warning}}
|
||||
bcmp(0, &x1, sizeof x1); // \
|
||||
// expected-warning{{second operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
|
||||
// expected-note {{explicitly cast the pointer to silence this warning}}
|
||||
|
||||
__builtin_memset(&x1, 0, sizeof x1); // \
|
||||
// expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
|
||||
|
|
Loading…
Reference in New Issue