-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang] Fix crash on invalid size in user-defined static_assert
message
#89420
Conversation
@llvm/pr-subscribers-clang Author: None (Sirraide) ChangesThis addresses two problems observed in #89407 wrt user-defined
This fixes #89407. Full diff: https://github.com/llvm/llvm-project/pull/89420.diff 3 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5ec0218aedfe86..85c0cf93ee732f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -87,9 +87,9 @@ def err_expr_not_cce : Error<
"call to 'size()'|call to 'data()'}0 is not a constant expression">;
def ext_cce_narrowing : ExtWarn<
"%select{case value|enumerator value|non-type template argument|"
- "array size|explicit specifier argument|noexcept specifier argument}0 "
- "%select{cannot be narrowed from type %2 to %3|"
- "evaluates to %2, which cannot be narrowed to type %3}1">,
+ "array size|explicit specifier argument|noexcept specifier argument|"
+ "call to 'size()'|call to 'data()'}0 %select{cannot be narrowed from "
+ "type %2 to %3|evaluates to %2, which cannot be narrowed to type %3}1">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def err_ice_not_integral : Error<
"%select{integer|integral}1 constant expression must have "
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 88c8eaf6ef9b6e..e1f060f77ccd9d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -16853,13 +16853,13 @@ bool Expr::EvaluateCharRangeAsString(std::string &Result,
if (!::EvaluateInteger(SizeExpression, SizeValue, Info))
return false;
- int64_t Size = SizeValue.getExtValue();
+ uint64_t Size = SizeValue.getZExtValue();
if (!::EvaluatePointer(PtrExpression, String, Info))
return false;
QualType CharTy = PtrExpression->getType()->getPointeeType();
- for (int64_t I = 0; I < Size; ++I) {
+ for (uint64_t I = 0; I < Size; ++I) {
APValue Char;
if (!handleLValueToRValueConversion(Info, PtrExpression, CharTy, String,
Char))
diff --git a/clang/test/SemaCXX/static-assert-cxx26.cpp b/clang/test/SemaCXX/static-assert-cxx26.cpp
index f4ede74f9214a4..7d896d8b365b74 100644
--- a/clang/test/SemaCXX/static-assert-cxx26.cpp
+++ b/clang/test/SemaCXX/static-assert-cxx26.cpp
@@ -341,3 +341,77 @@ struct Callable {
} data;
};
static_assert(false, Callable{}); // expected-error {{static assertion failed: hello}}
+
+namespace GH89407 {
+struct A {
+ constexpr __SIZE_TYPE__ size() const { return -1; }
+ constexpr const char* data() const { return ""; }
+};
+
+struct B {
+ constexpr long long size() const { return 18446744073709551615U; }
+ constexpr const char* data() const { return ""; }
+};
+
+struct C {
+ constexpr __int128 size() const { return -1; }
+ constexpr const char* data() const { return ""; }
+};
+
+struct D {
+ constexpr unsigned __int128 size() const { return -1; }
+ constexpr const char* data() const { return ""; }
+};
+
+struct E {
+ constexpr __SIZE_TYPE__ size() const { return 18446744073709551615U; }
+ constexpr const char* data() const { return ""; }
+};
+
+static_assert(true, A{}); // expected-error {{the message in this static assertion is not a constant expression}}
+ // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+static_assert(true, B{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in this static assertion is not a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+static_assert(true, C{}); // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in this static assertion is not a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+static_assert(true, D{}); // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in this static assertion is not a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+static_assert(true, E{}); // expected-error {{the message in this static assertion is not a constant expression}}
+ // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+
+static_assert(
+ false, // expected-error {{static assertion failed}}
+ A{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
+ // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+);
+
+static_assert(
+ false, // expected-error {{static assertion failed}}
+ B{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+);
+
+static_assert(
+ false, // expected-error {{static assertion failed}}
+ C{} // expected-error {{call to 'size()' evaluates to -1, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+);
+
+static_assert(
+ false, // expected-error {{static assertion failed}}
+ D{} // expected-error {{call to 'size()' evaluates to 340282366920938463463374607431768211455, which cannot be narrowed to type 'unsigned long'}}
+ // expected-error@-1 {{the message in a static assertion must be produced by a constant expression}}
+ // expected-note@-2 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+);
+
+static_assert(
+ false, // expected-error {{static assertion failed}}
+ E{} // expected-error {{the message in a static assertion must be produced by a constant expression}}
+ // expected-note@-1 {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
+);
+}
|
The change LGTM but it does need a release note |
Oh, yeah, I somehow forgot about that because I got distracted by the second bug; will do. |
This addresses two problems observed in #89407 wrt user-defined
static_assert
messages:Expr::EvaluateCharRangeAsString
, we were callinggetExtValue()
instead ofgetZExtValue()
, which would assert if a negative or very large number was returned fromsize()
.std::size_t
, attempting to diagnose that would crash becauseext_cce_narrowing
was missing two%select
cases.This fixes #89407.