From 048b253a9331f12ee931697844eefc9263d376fa Mon Sep 17 00:00:00 2001 From: a3d4 Date: Thu, 21 Apr 2022 01:44:25 +0200 Subject: [PATCH] Refix MSVC Debug crash --- libsolutil/Visitor.h | 13 ++++++- libyul/optimiser/StructuralSimplifier.cpp | 43 ++++++++++------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/libsolutil/Visitor.h b/libsolutil/Visitor.h index 497ed2f29..1147f9579 100644 --- a/libsolutil/Visitor.h +++ b/libsolutil/Visitor.h @@ -56,6 +56,17 @@ struct VisitorFallback { template R operator()(T&&) const { retur template<> struct VisitorFallback<> { template void operator()(T&&) const {} }; -template struct GenericVisitor: Visitors... { using Visitors::operator()...; }; +// MSVC. Empty base class optimization does not happen in some scenarios. +// Enforcing it with __declspec(empty_bases) avoids MSVC Debug test crash +// (Run-Time Check Failure #2 - Stack around the variable '....' was corrupted). +// See https://docs.microsoft.com/en-us/cpp/cpp/empty-bases, +// https://developercommunity.visualstudio.com/t/10005513. +#if defined(_MSC_VER) +#define SOLC_EMPTY_BASES __declspec(empty_bases) +#else +#define SOLC_EMPTY_BASES +#endif + +template struct SOLC_EMPTY_BASES GenericVisitor: Visitors... { using Visitors::operator()...; }; template GenericVisitor(Visitors...) -> GenericVisitor; } diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 0b80c42cd..ca8f94239 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -93,31 +93,26 @@ void StructuralSimplifier::operator()(Block& _block) void StructuralSimplifier::simplify(std::vector& _statements) { - // Explicit local variables ifLambda, switchLambda, forLoopLambda are created to avoid MSVC C++17 Debug test crash - // (Run-Time Check Failure #2 - Stack around the variable '....' was corrupted). - // As soon as the issue is fixed, this workaround can be removed. - auto ifLambda = [&](If& _ifStmt) -> OptionalStatements - { - if (expressionAlwaysTrue(*_ifStmt.condition)) - return {std::move(_ifStmt.body.statements)}; - else if (expressionAlwaysFalse(*_ifStmt.condition)) - return {vector{}}; - return {}; + util::GenericVisitor visitor{ + util::VisitorFallback{}, + [&](If& _ifStmt) -> OptionalStatements { + if (expressionAlwaysTrue(*_ifStmt.condition)) + return {std::move(_ifStmt.body.statements)}; + else if (expressionAlwaysFalse(*_ifStmt.condition)) + return {vector{}}; + return {}; + }, + [&](Switch& _switchStmt) -> OptionalStatements { + if (std::optional const constExprVal = hasLiteralValue(*_switchStmt.expression)) + return replaceConstArgSwitch(_switchStmt, constExprVal.value()); + return {}; + }, + [&](ForLoop& _forLoop) -> OptionalStatements { + if (expressionAlwaysFalse(*_forLoop.condition)) + return {std::move(_forLoop.pre.statements)}; + return {}; + } }; - auto switchLambda = [&](Switch& _switchStmt) -> OptionalStatements - { - if (std::optional const constExprVal = hasLiteralValue(*_switchStmt.expression)) - return replaceConstArgSwitch(_switchStmt, constExprVal.value()); - return {}; - }; - auto forLoopLambda = [&](ForLoop& _forLoop) -> OptionalStatements - { - if (expressionAlwaysFalse(*_forLoop.condition)) - return {std::move(_forLoop.pre.statements)}; - return {}; - }; - - util::GenericVisitor visitor{util::VisitorFallback{}, ifLambda, switchLambda, forLoopLambda}; util::iterateReplacing( _statements,