r194762 - Modern gcc is happy to constant evaluate __builtin_strlen in various cases
Richard Smith
richard-llvm at metafoo.co.uk
Thu Nov 14 18:10:04 PST 2013
Author: rsmith
Date: Thu Nov 14 20:10:04 2013
New Revision: 194762
URL: http://llvm.org/viewvc/llvm-project?rev=194762&view=rev
Log:
Modern gcc is happy to constant evaluate __builtin_strlen in various cases
where we didn't. Extend our constant evaluation for __builtin_strlen to handle
any constant array of chars, not just string literals, to match.
Modified:
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=194762&r1=194761&r2=194762&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Nov 14 20:10:04 2013
@@ -6133,22 +6133,47 @@ bool IntExprEvaluator::VisitCallExpr(con
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
// Fall through.
- case Builtin::BI__builtin_strlen:
- // As an extension, we support strlen() and __builtin_strlen() as constant
- // expressions when the argument is a string literal.
- if (const StringLiteral *S
- = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
+ case Builtin::BI__builtin_strlen: {
+ // As an extension, we support __builtin_strlen() as a constant expression,
+ // and support folding strlen() to a constant.
+ LValue String;
+ if (!EvaluatePointer(E->getArg(0), String, Info))
+ return false;
+
+ // Fast path: if it's a string literal, search the string value.
+ if (const StringLiteral *S = dyn_cast_or_null<StringLiteral>(
+ String.getLValueBase().dyn_cast<const Expr *>())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
- StringRef Str = S->getString();
- StringRef::size_type Pos = Str.find(0);
- if (Pos != StringRef::npos)
- Str = Str.substr(0, Pos);
-
- return Success(Str.size(), E);
+ StringRef Str = S->getBytes();
+ int64_t Off = String.Offset.getQuantity();
+ if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() &&
+ S->getCharByteWidth() == 1) {
+ Str = Str.substr(Off);
+
+ StringRef::size_type Pos = Str.find(0);
+ if (Pos != StringRef::npos)
+ Str = Str.substr(0, Pos);
+
+ return Success(Str.size(), E);
+ }
+
+ // Fall through to slow path to issue appropriate diagnostic.
}
-
- return Error(E);
+
+ // Slow path: scan the bytes of the string looking for the terminating 0.
+ QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+ for (uint64_t Strlen = 0; /**/; ++Strlen) {
+ APValue Char;
+ if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) ||
+ !Char.isInt())
+ return false;
+ if (!Char.getInt())
+ return Success(Strlen, E);
+ if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1))
+ return false;
+ }
+ }
case Builtin::BI__atomic_always_lock_free:
case Builtin::BI__atomic_is_lock_free:
@@ -6426,8 +6451,8 @@ bool DataRecursiveIntBinOpEvaluator::
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
Result = LHSVal;
- CharUnits AdditionalOffset = CharUnits::fromQuantity(
- RHSVal.getInt().getZExtValue());
+ CharUnits AdditionalOffset =
+ CharUnits::fromQuantity(RHSVal.getInt().getZExtValue());
if (E->getOpcode() == BO_Add)
Result.getLValueOffset() += AdditionalOffset;
else
@@ -6439,8 +6464,8 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Add &&
RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- Result.getLValueOffset() += CharUnits::fromQuantity(
- LHSVal.getInt().getZExtValue());
+ Result.getLValueOffset() +=
+ CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
return true;
}
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=194762&r1=194761&r2=194762&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Nov 14 20:10:04 2013
@@ -1824,3 +1824,42 @@ namespace PR17800 {
}
constexpr int k = run<1, 2, 3>();
}
+
+namespace BuiltinStrlen {
+ constexpr const char *a = "foo\0quux";
+ constexpr char b[] = "foo\0quux";
+ constexpr int f() { return 'u'; }
+ constexpr char c[] = { 'f', 'o', 'o', 0, 'q', f(), 'u', 'x', 0 };
+
+ static_assert(__builtin_strlen("foo") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux") == 3, "");
+ static_assert(__builtin_strlen("foo\0quux" + 4) == 4, "");
+
+ constexpr bool check(const char *p) {
+ return __builtin_strlen(p) == 3 &&
+ __builtin_strlen(p + 1) == 2 &&
+ __builtin_strlen(p + 2) == 1 &&
+ __builtin_strlen(p + 3) == 0 &&
+ __builtin_strlen(p + 4) == 4 &&
+ __builtin_strlen(p + 5) == 3 &&
+ __builtin_strlen(p + 6) == 2 &&
+ __builtin_strlen(p + 7) == 1 &&
+ __builtin_strlen(p + 8) == 0;
+ }
+
+ static_assert(check(a), "");
+ static_assert(check(b), "");
+ static_assert(check(c), "");
+
+ constexpr int over1 = __builtin_strlen(a + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+ constexpr int over2 = __builtin_strlen(b + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+ constexpr int over3 = __builtin_strlen(c + 9); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+
+ constexpr int under1 = __builtin_strlen(a - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+ constexpr int under2 = __builtin_strlen(b - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+ constexpr int under3 = __builtin_strlen(c - 1); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
+
+ // FIXME: The diagnostic here could be better.
+ constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator.
+ constexpr int bad = __builtin_strlen(d); // expected-error {{constant expression}} expected-note {{one-past-the-end}}
+}
More information about the cfe-commits
mailing list