From 0e5c7ddfb8f10c9b4c62802d25d60bc3f672ee17 Mon Sep 17 00:00:00 2001 From: Bartosz Przybylski Date: Fri, 4 Dec 2015 11:03:39 +0100 Subject: [PATCH] Make c++ defer looks like a swift one --- include/swift/Basic/Defer.h | 25 ++++++++++++++++--------- lib/Parse/ParseDecl.cpp | 4 ++-- lib/Sema/IterativeTypeChecker.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 8 ++++---- lib/Sema/TypeCheckExpr.cpp | 2 +- lib/Sema/TypeCheckProtocol.cpp | 12 ++++++------ 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/include/swift/Basic/Defer.h b/include/swift/Basic/Defer.h index d412db123b503..367b624a16d20 100644 --- a/include/swift/Basic/Defer.h +++ b/include/swift/Basic/Defer.h @@ -18,11 +18,12 @@ #ifndef __SWIFT_DEFER_H #define __SWIFT_DEFER_H +#include + namespace swift { template class DoAtScopeExit { F &Fn; - DoAtScopeExit(DoAtScopeExit&) = delete; void operator=(DoAtScopeExit&) = delete; public: DoAtScopeExit(F &Fn) : Fn(Fn){} @@ -30,8 +31,17 @@ namespace swift { Fn(); } }; + + namespace detail { + struct DeferTask {}; + template + DoAtScopeExit::type> operator+(DeferTask, F&& fn) { + return DoAtScopeExit::type>(fn); + } + } } + #define DEFER_CONCAT_IMPL(x, y) x##y #define DEFER_MACRO_CONCAT(x, y) DEFER_CONCAT_IMPL(x, y) @@ -39,16 +49,13 @@ namespace swift { /// This macro is used to register a function / lambda to be run on exit from a /// scope. Its typical use looks like: /// -/// defer([&]{ +/// defer { /// stuff -/// }) +/// }; /// -#define defer(x) \ - auto DEFER_MACRO_CONCAT(defer_func, __LINE__) = (x); \ - swift::DoAtScopeExit \ - DEFER_MACRO_CONCAT(defer_local, __LINE__)\ - (DEFER_MACRO_CONCAT(defer_func, __LINE__)); +#define defer \ + auto DEFER_MACRO_CONCAT(defer_func, __COUNTER__) = \ + ::swift::detail::DeferTask() + [&]() #endif - diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d0c969a210bf0..6d6d1f6b6086b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3643,7 +3643,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags, // No matter what error path we take, make sure the // PatternBindingDecl/TopLevel code block are added. - defer([&]{ + defer { // If we didn't parse any patterns, don't create the pattern binding decl. if (PBDEntries.empty()) return; @@ -3683,7 +3683,7 @@ ParserStatus Parser::parseDeclVar(ParseDeclOptions Flags, // specific spot to get it in before any accessors, which SILGen seems to // want. Decls.insert(Decls.begin()+NumDeclsInResult, PBD); - }); + }; do { Pattern *pattern; diff --git a/lib/Sema/IterativeTypeChecker.cpp b/lib/Sema/IterativeTypeChecker.cpp index d6cf18fcbce90..061c36e34460e 100644 --- a/lib/Sema/IterativeTypeChecker.cpp +++ b/lib/Sema/IterativeTypeChecker.cpp @@ -84,7 +84,7 @@ void IterativeTypeChecker::satisfy(TypeCheckRequest request) { // Add this request to the stack of active requests. ActiveRequests.push_back(request); - defer([&] { ActiveRequests.pop_back(); }); + defer { ActiveRequests.pop_back(); }; while (true) { // Process this requirement, enumerating dependencies if anything else needs diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index f83bfb31c7b7b..f0c730bf4e930 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -356,7 +356,7 @@ void TypeChecker::checkInheritanceClause(Decl *decl, { bool iBTC = decl->isBeingTypeChecked(); decl->setIsBeingTypeChecked(); - defer([&]{decl->setIsBeingTypeChecked(iBTC); }); + defer {decl->setIsBeingTypeChecked(iBTC); }; // Validate the type. if (validateType(inherited, DC, options, resolver)) { @@ -1219,9 +1219,9 @@ static void validatePatternBindingDecl(TypeChecker &tc, // On any path out of this function, make sure to mark the binding as done // being type checked. - defer([&]{ + defer { binding->setIsBeingTypeChecked(false); - }); + }; // Resolve the pattern. auto *pattern = tc.resolvePattern(binding->getPattern(entryNumber), @@ -6239,7 +6239,7 @@ static Type checkExtensionGenericParams( }; ext->setIsBeingTypeChecked(true); - defer([ext] { ext->setIsBeingTypeChecked(false); }); + defer { ext->setIsBeingTypeChecked(false); }; // Validate the generic type signature. bool invalid = false; diff --git a/lib/Sema/TypeCheckExpr.cpp b/lib/Sema/TypeCheckExpr.cpp index a16aaedb85e35..db6b90987214b 100644 --- a/lib/Sema/TypeCheckExpr.cpp +++ b/lib/Sema/TypeCheckExpr.cpp @@ -890,7 +890,7 @@ namespace { } // Recursively check the transitive captures. capturePath.push_back(func); - defer([&]{ capturePath.pop_back(); }); + defer { capturePath.pop_back(); }; for (auto capture : func->getCaptureInfo().getCaptures()) if (!validateForwardCapture(capture.getDecl())) return false; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 8b6f573753921..669186aa5c311 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2922,9 +2922,9 @@ void ConformanceChecker::resolveTypeWitnesses() { // Track when we are checking type witnesses. ProtocolConformanceState initialState = Conformance->getState(); Conformance->setState(ProtocolConformanceState::CheckingTypeWitnesses); - defer([&] { + defer { Conformance->setState(initialState); - }); + }; for (auto member : Proto->getMembers()) { auto assocType = dyn_cast(member); @@ -3251,11 +3251,11 @@ void ConformanceChecker::resolveTypeWitnesses() { valueWitnesses.push_back({inferredReq.first, witnessReq.Witness}); if (witnessReq.Witness->getDeclContext()->isProtocolExtensionContext()) ++numValueWitnessesInProtocolExtensions; - defer([&]{ + defer { if (witnessReq.Witness->getDeclContext()->isProtocolExtensionContext()) --numValueWitnessesInProtocolExtensions; valueWitnesses.pop_back(); - }); + }; // Introduce each of the type witnesses into the hash table. bool failed = false; @@ -3635,7 +3635,7 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) { // Note that we're resolving this witness. assert(ResolvingWitnesses.count(requirement) == 0 && "Currently resolving"); ResolvingWitnesses.insert(requirement); - defer([&]{ ResolvingWitnesses.erase(requirement); }); + defer { ResolvingWitnesses.erase(requirement); }; // Make sure we've validated the requirement. if (!requirement->hasType()) @@ -3934,7 +3934,7 @@ checkConformsToProtocol(TypeChecker &TC, // Note that we are checking this conformance now. conformance->setState(ProtocolConformanceState::Checking); - defer([&] { conformance->setState(ProtocolConformanceState::Complete); }); + defer { conformance->setState(ProtocolConformanceState::Complete); }; // If the protocol requires a class, non-classes are a non-starter. if (Proto->requiresClass() && !canT->getClassOrBoundGenericClass()) {