Commit a7ca5b0f authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] better static assert error messages

When mksnapshot fails on a static assert in Torque, print the
statement and position from the Torque source. To enable special
treatment, change the syntax of static asserts in Torque
from StaticAssert() to static_assert() to align with assert() and
check() statements.

Bug: v8:7793
Change-Id: Idda8e3c342bdcefc893ff297f8d7727d2734c221
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2317314
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarSeth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#69069}
parent c0ed24a0
...@@ -473,7 +473,6 @@ extern macro SelectBooleanConstant(bool): Boolean; ...@@ -473,7 +473,6 @@ extern macro SelectBooleanConstant(bool): Boolean;
extern macro Print(constexpr string); extern macro Print(constexpr string);
extern macro Print(constexpr string, Object); extern macro Print(constexpr string, Object);
extern macro Comment(constexpr string); extern macro Comment(constexpr string);
extern macro StaticAssert(bool);
extern macro Print(Object); extern macro Print(Object);
extern macro DebugBreak(); extern macro DebugBreak();
...@@ -1618,7 +1617,7 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)( ...@@ -1618,7 +1617,7 @@ transitioning builtin FastCreateDataProperty(implicit context: Context)(
} }
macro VerifiedUnreachable(): never { macro VerifiedUnreachable(): never {
StaticAssert(false); static_assert(false);
unreachable; unreachable;
} }
......
...@@ -117,7 +117,7 @@ IfInBounds(String, uintptr, uintptr), IfOutOfBounds { ...@@ -117,7 +117,7 @@ IfInBounds(String, uintptr, uintptr), IfOutOfBounds {
// check. // check.
const kMaxStringLengthFitsSmi: constexpr bool = const kMaxStringLengthFitsSmi: constexpr bool =
kStringMaxLengthUintptr < kSmiMaxValue; kStringMaxLengthUintptr < kSmiMaxValue;
StaticAssert(kMaxStringLengthFitsSmi); static_assert(kMaxStringLengthFitsSmi);
if (index >= length) goto IfOutOfBounds; if (index >= length) goto IfOutOfBounds;
goto IfInBounds(string, index, length); goto IfInBounds(string, index, length);
} }
......
...@@ -49,7 +49,7 @@ FromConstexpr<Number, constexpr int31>(i: constexpr int31): Number { ...@@ -49,7 +49,7 @@ FromConstexpr<Number, constexpr int31>(i: constexpr int31): Number {
} }
FromConstexpr<uint8, constexpr int31>(i: constexpr int31): uint8 { FromConstexpr<uint8, constexpr int31>(i: constexpr int31): uint8 {
const i: uint32 = i; const i: uint32 = i;
StaticAssert(i <= 255); static_assert(i <= 255);
return %RawDownCast<uint8>(i); return %RawDownCast<uint8>(i);
} }
FromConstexpr<Number, constexpr Smi>(s: constexpr Smi): Number { FromConstexpr<Number, constexpr Smi>(s: constexpr Smi): Number {
......
...@@ -100,7 +100,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( ...@@ -100,7 +100,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)(
primaryHandler = promiseReaction.fulfill_handler; primaryHandler = promiseReaction.fulfill_handler;
secondaryHandler = promiseReaction.reject_handler; secondaryHandler = promiseReaction.reject_handler;
} else { } else {
StaticAssert(reactionType == kPromiseReactionReject); static_assert(reactionType == kPromiseReactionReject);
primaryHandler = promiseReaction.reject_handler; primaryHandler = promiseReaction.reject_handler;
secondaryHandler = promiseReaction.fulfill_handler; secondaryHandler = promiseReaction.fulfill_handler;
} }
...@@ -114,7 +114,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( ...@@ -114,7 +114,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)(
// Morph {current} from a PromiseReaction into a PromiseReactionJobTask // Morph {current} from a PromiseReaction into a PromiseReactionJobTask
// and schedule that on the microtask queue. We try to minimize the number // and schedule that on the microtask queue. We try to minimize the number
// of stores here to avoid screwing up the store buffer. // of stores here to avoid screwing up the store buffer.
StaticAssert( static_assert(
kPromiseReactionSize == kPromiseReactionSize ==
kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks); kPromiseReactionJobTaskSizeOfAllPromiseReactionJobTasks);
if constexpr (reactionType == kPromiseReactionFulfill) { if constexpr (reactionType == kPromiseReactionFulfill) {
...@@ -125,14 +125,14 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( ...@@ -125,14 +125,14 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)(
promiseReactionJobTask.argument = argument; promiseReactionJobTask.argument = argument;
promiseReactionJobTask.context = handlerContext; promiseReactionJobTask.context = handlerContext;
EnqueueMicrotask(handlerContext, promiseReactionJobTask); EnqueueMicrotask(handlerContext, promiseReactionJobTask);
StaticAssert( static_assert(
kPromiseReactionFulfillHandlerOffset == kPromiseReactionFulfillHandlerOffset ==
kPromiseReactionJobTaskHandlerOffset); kPromiseReactionJobTaskHandlerOffset);
StaticAssert( static_assert(
kPromiseReactionPromiseOrCapabilityOffset == kPromiseReactionPromiseOrCapabilityOffset ==
kPromiseReactionJobTaskPromiseOrCapabilityOffset); kPromiseReactionJobTaskPromiseOrCapabilityOffset);
} else { } else {
StaticAssert(reactionType == kPromiseReactionReject); static_assert(reactionType == kPromiseReactionReject);
*UnsafeConstCast(&promiseReaction.map) = *UnsafeConstCast(&promiseReaction.map) =
PromiseRejectReactionJobTaskMapConstant(); PromiseRejectReactionJobTaskMapConstant();
const promiseReactionJobTask = const promiseReactionJobTask =
...@@ -141,7 +141,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)( ...@@ -141,7 +141,7 @@ transitioning macro MorphAndEnqueuePromiseReaction(implicit context: Context)(
promiseReactionJobTask.context = handlerContext; promiseReactionJobTask.context = handlerContext;
promiseReactionJobTask.handler = primaryHandler; promiseReactionJobTask.handler = primaryHandler;
EnqueueMicrotask(handlerContext, promiseReactionJobTask); EnqueueMicrotask(handlerContext, promiseReactionJobTask);
StaticAssert( static_assert(
kPromiseReactionPromiseOrCapabilityOffset == kPromiseReactionPromiseOrCapabilityOffset ==
kPromiseReactionJobTaskPromiseOrCapabilityOffset); kPromiseReactionJobTaskPromiseOrCapabilityOffset);
} }
......
...@@ -30,7 +30,7 @@ macro RejectPromiseReactionJob( ...@@ -30,7 +30,7 @@ macro RejectPromiseReactionJob(
} }
} }
} else { } else {
StaticAssert(reactionType == kPromiseReactionFulfill); static_assert(reactionType == kPromiseReactionFulfill);
// We have to call out to the dedicated PromiseRejectReactionJob // We have to call out to the dedicated PromiseRejectReactionJob
// builtin here, instead of just doing the work inline, as otherwise // builtin here, instead of just doing the work inline, as otherwise
// the catch predictions in the debugger will be wrong, which just // the catch predictions in the debugger will be wrong, which just
...@@ -79,7 +79,7 @@ macro PromiseReactionJob( ...@@ -79,7 +79,7 @@ macro PromiseReactionJob(
return FuflfillPromiseReactionJob( return FuflfillPromiseReactionJob(
context, promiseOrCapability, argument, reactionType); context, promiseOrCapability, argument, reactionType);
} else { } else {
StaticAssert(reactionType == kPromiseReactionReject); static_assert(reactionType == kPromiseReactionReject);
return RejectPromiseReactionJob( return RejectPromiseReactionJob(
context, promiseOrCapability, argument, reactionType); context, promiseOrCapability, argument, reactionType);
} }
......
...@@ -110,7 +110,7 @@ transitioning macro RegExpPrototypeMatchBody(implicit context: Context)( ...@@ -110,7 +110,7 @@ transitioning macro RegExpPrototypeMatchBody(implicit context: Context)(
// length is less than the maximal Smi value. // length is less than the maximal Smi value.
const kMaxStringLengthFitsSmi: constexpr bool = const kMaxStringLengthFitsSmi: constexpr bool =
kStringMaxLengthUintptr < kSmiMaxValue; kStringMaxLengthUintptr < kSmiMaxValue;
StaticAssert(kMaxStringLengthFitsSmi); static_assert(kMaxStringLengthFitsSmi);
assert(TaggedIsPositiveSmi(newLastIndex)); assert(TaggedIsPositiveSmi(newLastIndex));
} }
......
...@@ -219,6 +219,8 @@ macro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject): ...@@ -219,6 +219,8 @@ macro DownCastForTorqueClass<T : type extends HeapObject>(o: HeapObject):
return %RawDownCast<T>(o); return %RawDownCast<T>(o);
} }
extern macro StaticAssert(bool, constexpr string);
} // namespace torque_internal } // namespace torque_internal
// Indicates that an array-field should not be initialized. // Indicates that an array-field should not be initialized.
......
...@@ -3083,7 +3083,9 @@ void InstructionSelector::VisitUnreachable(Node* node) { ...@@ -3083,7 +3083,9 @@ void InstructionSelector::VisitUnreachable(Node* node) {
void InstructionSelector::VisitStaticAssert(Node* node) { void InstructionSelector::VisitStaticAssert(Node* node) {
Node* asserted = node->InputAt(0); Node* asserted = node->InputAt(0);
asserted->Print(4); asserted->Print(4);
FATAL("Expected turbofan static assert to hold, but got non-true input!\n"); FATAL(
"Expected Turbofan static assert to hold, but got non-true input:\n %s",
StaticAssertSourceOf(node->op()));
} }
void InstructionSelector::VisitDeadValue(Node* node) { void InstructionSelector::VisitDeadValue(Node* node) {
......
...@@ -495,8 +495,8 @@ void CodeAssembler::Comment(std::string str) { ...@@ -495,8 +495,8 @@ void CodeAssembler::Comment(std::string str) {
raw_assembler()->Comment(str); raw_assembler()->Comment(str);
} }
void CodeAssembler::StaticAssert(TNode<BoolT> value) { void CodeAssembler::StaticAssert(TNode<BoolT> value, const char* source) {
raw_assembler()->StaticAssert(value); raw_assembler()->StaticAssert(value, source);
} }
void CodeAssembler::SetSourcePosition(const char* file, int line) { void CodeAssembler::SetSourcePosition(const char* file, int line) {
......
...@@ -597,7 +597,8 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -597,7 +597,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Comment(s.str()); Comment(s.str());
} }
void StaticAssert(TNode<BoolT> value); void StaticAssert(TNode<BoolT> value,
const char* source = "unknown position");
// The following methods refer to source positions in CSA or Torque code // The following methods refer to source positions in CSA or Torque code
// compiled during mksnapshot, not JS compiled at runtime. // compiled during mksnapshot, not JS compiled at runtime.
......
...@@ -455,22 +455,21 @@ IfValueParameters const& IfValueParametersOf(const Operator* op) { ...@@ -455,22 +455,21 @@ IfValueParameters const& IfValueParametersOf(const Operator* op) {
return OpParameter<IfValueParameters>(op); return OpParameter<IfValueParameters>(op);
} }
#define COMMON_CACHED_OP_LIST(V) \ #define COMMON_CACHED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \ V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
V(Unreachable, Operator::kFoldable, 0, 1, 1, 1, 1, 0) \ V(Unreachable, Operator::kFoldable, 0, 1, 1, 1, 1, 0) \
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \ V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
V(IfException, Operator::kKontrol, 0, 1, 1, 1, 1, 1) \ V(IfException, Operator::kKontrol, 0, 1, 1, 1, 1, 1) \
V(Throw, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ V(Throw, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \ V(Terminate, Operator::kKontrol, 0, 1, 1, 0, 0, 1) \
V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \ V(LoopExit, Operator::kKontrol, 0, 0, 2, 0, 0, 1) \
V(LoopExitValue, Operator::kPure, 1, 0, 1, 1, 0, 0) \ V(LoopExitValue, Operator::kPure, 1, 0, 1, 1, 0, 0) \
V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \ V(LoopExitEffect, Operator::kNoThrow, 0, 1, 1, 0, 1, 0) \
V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \ V(Checkpoint, Operator::kKontrol, 0, 1, 1, 0, 1, 0) \
V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \ V(FinishRegion, Operator::kKontrol, 1, 1, 0, 1, 1, 0) \
V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0) \ V(Retain, Operator::kKontrol, 1, 1, 0, 0, 1, 0)
V(StaticAssert, Operator::kFoldable, 1, 1, 0, 0, 1, 0)
#define CACHED_BRANCH_LIST(V) \ #define CACHED_BRANCH_LIST(V) \
V(None, CriticalSafetyCheck) \ V(None, CriticalSafetyCheck) \
...@@ -939,6 +938,12 @@ const Operator* CommonOperatorBuilder::Return(int value_input_count) { ...@@ -939,6 +938,12 @@ const Operator* CommonOperatorBuilder::Return(int value_input_count) {
value_input_count + 1, 1, 1, 0, 0, 1); // counts value_input_count + 1, 1, 1, 0, 0, 1); // counts
} }
const Operator* CommonOperatorBuilder::StaticAssert(const char* source) {
return zone()->New<Operator1<const char*>>(
IrOpcode::kStaticAssert, Operator::kFoldable, "StaticAssert", 1, 1, 0, 0,
1, 0, source);
}
const Operator* CommonOperatorBuilder::Branch(BranchHint hint, const Operator* CommonOperatorBuilder::Branch(BranchHint hint,
IsSafetyCheck is_safety_check) { IsSafetyCheck is_safety_check) {
#define CACHED_BRANCH(Hint, IsCheck) \ #define CACHED_BRANCH(Hint, IsCheck) \
...@@ -1248,6 +1253,11 @@ const StringConstantBase* StringConstantBaseOf(const Operator* op) { ...@@ -1248,6 +1253,11 @@ const StringConstantBase* StringConstantBaseOf(const Operator* op) {
return OpParameter<const StringConstantBase*>(op); return OpParameter<const StringConstantBase*>(op);
} }
const char* StaticAssertSourceOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kStaticAssert, op->opcode());
return OpParameter<const char*>(op);
}
const Operator* CommonOperatorBuilder::RelocatableInt32Constant( const Operator* CommonOperatorBuilder::RelocatableInt32Constant(
int32_t value, RelocInfo::Mode rmode) { int32_t value, RelocInfo::Mode rmode) {
return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // -- return zone()->New<Operator1<RelocatablePtrConstantInfo>>( // --
......
...@@ -449,6 +449,8 @@ V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op) ...@@ -449,6 +449,8 @@ V8_EXPORT_PRIVATE Handle<HeapObject> HeapConstantOf(const Operator* op)
const StringConstantBase* StringConstantBaseOf(const Operator* op) const StringConstantBase* StringConstantBaseOf(const Operator* op)
V8_WARN_UNUSED_RESULT; V8_WARN_UNUSED_RESULT;
const char* StaticAssertSourceOf(const Operator* op);
// Interface for building common operators that can be used at any level of IR, // Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level. // including JavaScript, mid-level, and low-level.
class V8_EXPORT_PRIVATE CommonOperatorBuilder final class V8_EXPORT_PRIVATE CommonOperatorBuilder final
...@@ -459,7 +461,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final ...@@ -459,7 +461,7 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
const Operator* Dead(); const Operator* Dead();
const Operator* DeadValue(MachineRepresentation rep); const Operator* DeadValue(MachineRepresentation rep);
const Operator* Unreachable(); const Operator* Unreachable();
const Operator* StaticAssert(); const Operator* StaticAssert(const char* source);
const Operator* End(size_t control_input_count); const Operator* End(size_t control_input_count);
const Operator* Branch(BranchHint = BranchHint::kNone, const Operator* Branch(BranchHint = BranchHint::kNone,
IsSafetyCheck = IsSafetyCheck::kSafetyCheck); IsSafetyCheck = IsSafetyCheck::kSafetyCheck);
......
...@@ -285,7 +285,8 @@ Reduction JSIntrinsicLowering::ReduceTurbofanStaticAssert(Node* node) { ...@@ -285,7 +285,8 @@ Reduction JSIntrinsicLowering::ReduceTurbofanStaticAssert(Node* node) {
} else { } else {
Node* value = NodeProperties::GetValueInput(node, 0); Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* assert = graph()->NewNode(common()->StaticAssert(), value, effect); Node* assert = graph()->NewNode(
common()->StaticAssert("%TurbofanStaticAssert"), value, effect);
ReplaceWithValue(node, node, assert, nullptr); ReplaceWithValue(node, node, assert, nullptr);
} }
return Changed(jsgraph_->UndefinedConstant()); return Changed(jsgraph_->UndefinedConstant());
......
...@@ -680,8 +680,8 @@ void RawMachineAssembler::Comment(const std::string& msg) { ...@@ -680,8 +680,8 @@ void RawMachineAssembler::Comment(const std::string& msg) {
AddNode(machine()->Comment(zone_buffer)); AddNode(machine()->Comment(zone_buffer));
} }
void RawMachineAssembler::StaticAssert(Node* value) { void RawMachineAssembler::StaticAssert(Node* value, const char* source) {
AddNode(common()->StaticAssert(), value); AddNode(common()->StaticAssert(source), value);
} }
Node* RawMachineAssembler::CallN(CallDescriptor* call_descriptor, Node* RawMachineAssembler::CallN(CallDescriptor* call_descriptor,
......
...@@ -967,7 +967,7 @@ class V8_EXPORT_PRIVATE RawMachineAssembler { ...@@ -967,7 +967,7 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
void DebugBreak(); void DebugBreak();
void Unreachable(); void Unreachable();
void Comment(const std::string& msg); void Comment(const std::string& msg);
void StaticAssert(Node* value); void StaticAssert(Node* value, const char* source);
#if DEBUG #if DEBUG
void Bind(RawMachineLabel* label, AssemblerDebugInfo info); void Bind(RawMachineLabel* label, AssemblerDebugInfo info);
......
...@@ -709,13 +709,14 @@ struct DebugStatement : Statement { ...@@ -709,13 +709,14 @@ struct DebugStatement : Statement {
struct AssertStatement : Statement { struct AssertStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(AssertStatement) DEFINE_AST_NODE_LEAF_BOILERPLATE(AssertStatement)
AssertStatement(SourcePosition pos, bool debug_only, Expression* expression, enum class AssertKind { kAssert, kCheck, kStaticAssert };
AssertStatement(SourcePosition pos, AssertKind kind, Expression* expression,
std::string source) std::string source)
: Statement(kKind, pos), : Statement(kKind, pos),
debug_only(debug_only), kind(kind),
expression(expression), expression(expression),
source(std::move(source)) {} source(std::move(source)) {}
bool debug_only; AssertKind kind;
Expression* expression; Expression* expression;
std::string source; std::string source;
}; };
......
...@@ -17,6 +17,7 @@ namespace torque { ...@@ -17,6 +17,7 @@ namespace torque {
static const char* const CONSTEXPR_TYPE_PREFIX = "constexpr "; static const char* const CONSTEXPR_TYPE_PREFIX = "constexpr ";
static const char* const NEVER_TYPE_STRING = "never"; static const char* const NEVER_TYPE_STRING = "never";
static const char* const CONSTEXPR_BOOL_TYPE_STRING = "constexpr bool"; static const char* const CONSTEXPR_BOOL_TYPE_STRING = "constexpr bool";
static const char* const CONSTEXPR_STRING_TYPE_STRING = "constexpr string";
static const char* const CONSTEXPR_INTPTR_TYPE_STRING = "constexpr intptr"; static const char* const CONSTEXPR_INTPTR_TYPE_STRING = "constexpr intptr";
static const char* const CONSTEXPR_INSTANCE_TYPE_TYPE_STRING = static const char* const CONSTEXPR_INSTANCE_TYPE_TYPE_STRING =
"constexpr InstanceType"; "constexpr InstanceType";
...@@ -75,6 +76,7 @@ static const char* const UNINITIALIZED_ITERATOR_TYPE_STRING = ...@@ -75,6 +76,7 @@ static const char* const UNINITIALIZED_ITERATOR_TYPE_STRING =
static const char* const GENERIC_TYPE_INSTANTIATION_NAMESPACE_STRING = static const char* const GENERIC_TYPE_INSTANTIATION_NAMESPACE_STRING =
"_generic_type_instantiation_namespace"; "_generic_type_instantiation_namespace";
static const char* const FIXED_ARRAY_BASE_TYPE_STRING = "FixedArrayBase"; static const char* const FIXED_ARRAY_BASE_TYPE_STRING = "FixedArrayBase";
static const char* const STATIC_ASSERT_MACRO_STRING = "StaticAssert";
static const char* const ANNOTATION_GENERATE_PRINT = "@generatePrint"; static const char* const ANNOTATION_GENERATE_PRINT = "@generatePrint";
static const char* const ANNOTATION_NO_VERIFIER = "@noVerifier"; static const char* const ANNOTATION_NO_VERIFIER = "@noVerifier";
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/base/optional.h" #include "src/base/optional.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/torque/constants.h"
#include "src/torque/csa-generator.h" #include "src/torque/csa-generator.h"
#include "src/torque/declaration-visitor.h" #include "src/torque/declaration-visitor.h"
#include "src/torque/global-context.h" #include "src/torque/global-context.h"
...@@ -1047,7 +1048,19 @@ std::string FormatAssertSource(const std::string& str) { ...@@ -1047,7 +1048,19 @@ std::string FormatAssertSource(const std::string& str) {
} // namespace } // namespace
const Type* ImplementationVisitor::Visit(AssertStatement* stmt) { const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
bool do_check = !stmt->debug_only || GlobalContext::force_assert_statements(); if (stmt->kind == AssertStatement::AssertKind::kStaticAssert) {
std::string message =
"static_assert(" + stmt->source + ") at " + ToString(stmt->pos);
GenerateCall(QualifiedName({"", TORQUE_INTERNAL_NAMESPACE_STRING},
STATIC_ASSERT_MACRO_STRING),
Arguments{{Visit(stmt->expression),
VisitResult(TypeOracle::GetConstexprStringType(),
StringLiteralQuote(message))},
{}});
return TypeOracle::GetVoidType();
}
bool do_check = stmt->kind != AssertStatement::AssertKind::kAssert ||
GlobalContext::force_assert_statements();
#if defined(DEBUG) #if defined(DEBUG)
do_check = true; do_check = true;
#endif #endif
......
...@@ -487,11 +487,20 @@ base::Optional<ParseResult> MakeParameterList( ...@@ -487,11 +487,20 @@ base::Optional<ParseResult> MakeParameterList(
base::Optional<ParseResult> MakeAssertStatement( base::Optional<ParseResult> MakeAssertStatement(
ParseResultIterator* child_results) { ParseResultIterator* child_results) {
auto kind = child_results->NextAs<Identifier*>()->value; auto kind_string = child_results->NextAs<Identifier*>()->value;
auto expr_with_source = child_results->NextAs<ExpressionWithSource>(); auto expr_with_source = child_results->NextAs<ExpressionWithSource>();
DCHECK(kind == "assert" || kind == "check"); AssertStatement::AssertKind kind;
if (kind_string == "assert") {
kind = AssertStatement::AssertKind::kAssert;
} else if (kind_string == "check") {
kind = AssertStatement::AssertKind::kCheck;
} else if (kind_string == "static_assert") {
kind = AssertStatement::AssertKind::kStaticAssert;
} else {
UNREACHABLE();
}
Statement* result = MakeNode<AssertStatement>( Statement* result = MakeNode<AssertStatement>(
kind == "assert", expr_with_source.expression, expr_with_source.source); kind, expr_with_source.expression, expr_with_source.source);
return ParseResult{result}; return ParseResult{result};
} }
...@@ -2400,8 +2409,8 @@ struct TorqueGrammar : Grammar { ...@@ -2400,8 +2409,8 @@ struct TorqueGrammar : Grammar {
MakeTypeswitchStatement), MakeTypeswitchStatement),
Rule({Token("try"), &block, List<TryHandler*>(&tryHandler)}, Rule({Token("try"), &block, List<TryHandler*>(&tryHandler)},
MakeTryLabelExpression), MakeTryLabelExpression),
Rule({OneOf({"assert", "check"}), Token("("), &expressionWithSource, Rule({OneOf({"assert", "check", "static_assert"}), Token("("),
Token(")"), Token(";")}, &expressionWithSource, Token(")"), Token(";")},
MakeAssertStatement), MakeAssertStatement),
Rule({Token("while"), Token("("), expression, Token(")"), &statement}, Rule({Token("while"), Token("("), expression, Token(")"), &statement},
MakeWhileStatement), MakeWhileStatement),
......
...@@ -166,6 +166,10 @@ class TypeOracle : public ContextualClass<TypeOracle> { ...@@ -166,6 +166,10 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return Get().GetBuiltinType(CONSTEXPR_BOOL_TYPE_STRING); return Get().GetBuiltinType(CONSTEXPR_BOOL_TYPE_STRING);
} }
static const Type* GetConstexprStringType() {
return Get().GetBuiltinType(CONSTEXPR_STRING_TYPE_STRING);
}
static const Type* GetConstexprIntPtrType() { static const Type* GetConstexprIntPtrType() {
return Get().GetBuiltinType(CONSTEXPR_INTPTR_TYPE_STRING); return Get().GetBuiltinType(CONSTEXPR_INTPTR_TYPE_STRING);
} }
......
...@@ -908,7 +908,7 @@ macro TestSliceEnumeration(implicit context: Context)(): Undefined { ...@@ -908,7 +908,7 @@ macro TestSliceEnumeration(implicit context: Context)(): Undefined {
@export @export
macro TestStaticAssert() { macro TestStaticAssert() {
StaticAssert(1 + 2 == 3); static_assert(1 + 2 == 3);
} }
class SmiBox extends HeapObject { class SmiBox extends HeapObject {
...@@ -926,12 +926,12 @@ macro TestLoadEliminationFixed(implicit context: Context)() { ...@@ -926,12 +926,12 @@ macro TestLoadEliminationFixed(implicit context: Context)() {
const v1 = box.value; const v1 = box.value;
box.unrelated = 999; box.unrelated = 999;
const v2 = (box.unrelated == 0) ? box.value : box.value; const v2 = (box.unrelated == 0) ? box.value : box.value;
StaticAssert(TaggedEqual(v1, v2)); static_assert(TaggedEqual(v1, v2));
box.value = 11; box.value = 11;
const v3 = box.value; const v3 = box.value;
const eleven: Smi = 11; const eleven: Smi = 11;
StaticAssert(TaggedEqual(v3, eleven)); static_assert(TaggedEqual(v3, eleven));
} }
@export @export
...@@ -942,8 +942,8 @@ macro TestLoadEliminationVariable(implicit context: Context)() { ...@@ -942,8 +942,8 @@ macro TestLoadEliminationVariable(implicit context: Context)() {
const u1 = a.objects[box.value + 2]; const u1 = a.objects[box.value + 2];
const v2 = a.objects[box.value]; const v2 = a.objects[box.value];
const u2 = a.objects[box.value + 2]; const u2 = a.objects[box.value + 2];
StaticAssert(TaggedEqual(v1, v2)); static_assert(TaggedEqual(v1, v2));
StaticAssert(TaggedEqual(u1, u2)); static_assert(TaggedEqual(u1, u2));
} }
@export @export
...@@ -954,7 +954,7 @@ macro TestRedundantArrayElementCheck(implicit context: Context)(): Smi { ...@@ -954,7 +954,7 @@ macro TestRedundantArrayElementCheck(implicit context: Context)(): Smi {
if (a.objects[i] == TheHole) { if (a.objects[i] == TheHole) {
return -1; return -1;
} else { } else {
StaticAssert(false); static_assert(false);
} }
} }
} }
...@@ -1029,9 +1029,9 @@ macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi) { ...@@ -1029,9 +1029,9 @@ macro TestBranchOnBoolOptimization(implicit context: Context)(input: Smi) {
// If the two branches get combined into one, we should be able to determine // If the two branches get combined into one, we should be able to determine
// the value of {box} statically. // the value of {box} statically.
if (BranchAndWriteResult(input, box)) { if (BranchAndWriteResult(input, box)) {
StaticAssert(box.value == 1); static_assert(box.value == 1);
} else { } else {
StaticAssert(box.value == 2); static_assert(box.value == 2);
} }
} }
...@@ -1135,23 +1135,23 @@ macro TestBitFieldMultipleFlags(a: bool, b: int32, c: bool) { ...@@ -1135,23 +1135,23 @@ macro TestBitFieldMultipleFlags(a: bool, b: int32, c: bool) {
const f = TestBitFieldStruct4{a: a, b: b, c: c}; const f = TestBitFieldStruct4{a: a, b: b, c: c};
let simpleExpression = f.a & f.b == 3 & !f.c; let simpleExpression = f.a & f.b == 3 & !f.c;
let expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(1 | 3 << 1); let expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(1 | 3 << 1);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
simpleExpression = !f.a & f.b == 4 & f.c; simpleExpression = !f.a & f.b == 4 & f.c;
expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(4 << 1 | 1 << 4); expectedReduction = (Signed(f) & 0x1f) == Convert<int32>(4 << 1 | 1 << 4);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
simpleExpression = f.b == 0 & f.c; simpleExpression = f.b == 0 & f.c;
expectedReduction = (Signed(f) & 0x1e) == Convert<int32>(1 << 4); expectedReduction = (Signed(f) & 0x1e) == Convert<int32>(1 << 4);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
simpleExpression = f.a & f.c; simpleExpression = f.a & f.c;
expectedReduction = (Signed(f) & 0x11) == Convert<int32>(1 | 1 << 4); expectedReduction = (Signed(f) & 0x11) == Convert<int32>(1 | 1 << 4);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
const f2 = TestBitFieldStruct5{b: b, a: a, c: c}; const f2 = TestBitFieldStruct5{b: b, a: a, c: c};
simpleExpression = !f2.a & f2.b == 1234 & f2.c; simpleExpression = !f2.a & f2.b == 1234 & f2.c;
expectedReduction = (Signed(f2) & 0x1fffff) == Convert<int32>(1234 | 1 << 20); expectedReduction = (Signed(f2) & 0x1fffff) == Convert<int32>(1234 | 1 << 20);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
simpleExpression = !f2.a & !f2.c; simpleExpression = !f2.a & !f2.c;
expectedReduction = (Signed(f2) & 0x180000) == Convert<int32>(0); expectedReduction = (Signed(f2) & 0x180000) == Convert<int32>(0);
StaticAssert(simpleExpression == expectedReduction); static_assert(simpleExpression == expectedReduction);
} }
@export @export
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment