diff options
author | Clement Courbet <courbet@google.com> | 2019-02-14 12:00:34 +0000 |
---|---|---|
committer | Clement Courbet <courbet@google.com> | 2019-02-14 12:00:34 +0000 |
commit | 8cdd2381793911f203f4d2cbdb54b257673cd585 (patch) | |
tree | 1feaf6a00304235bee71cc95cf9b9eef034377b3 | |
parent | 5773155aa1b1e219b140ecdb61f207581211edbf (diff) | |
download | clang-8cdd2381793911f203f4d2cbdb54b257673cd585.tar.gz |
[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
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@354023 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/Builtins.def | 3 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 6 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 16 | ||||
-rw-r--r-- | test/Analysis/bstring.c | 3 | ||||
-rw-r--r-- | test/Analysis/security-syntax-checks.m | 2 | ||||
-rw-r--r-- | test/SemaCXX/constexpr-string.cpp | 49 | ||||
-rw-r--r-- | test/SemaCXX/warn-bad-memaccess.cpp | 9 |
8 files changed, 86 insertions, 18 deletions
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 2e8c6d9712..b5466c9d7a 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -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 diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 98962461a7..4f49bd7987 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -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")) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 19e6b53b09..c08e8e689d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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 || diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4b5c68a7bd..c8e72adb5e 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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( diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c index e8c3021f27..0fb807dc55 100644 --- a/test/Analysis/bstring.c +++ b/test/Analysis/bstring.c @@ -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 */ diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m index 68fc4b471a..a3efd53d4b 100644 --- a/test/Analysis/security-syntax-checks.m +++ b/test/Analysis/security-syntax-checks.m @@ -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()}} diff --git a/test/SemaCXX/constexpr-string.cpp b/test/SemaCXX/constexpr-string.cpp index c348c0ff74..f540be8f8e 100644 --- a/test/SemaCXX/constexpr-string.cpp +++ b/test/SemaCXX/constexpr-string.cpp @@ -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 { diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp index 55ce4a0da0..c7320901fc 100644 --- a/test/SemaCXX/warn-bad-memaccess.cpp +++ b/test/SemaCXX/warn-bad-memaccess.cpp @@ -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}} \ |