diff --git a/CodeGenerator.cpp b/CodeGenerator.cpp index 22667372..7edcc779 100644 --- a/CodeGenerator.cpp +++ b/CodeGenerator.cpp @@ -211,6 +211,97 @@ class LambdaNameOnlyCodeGenerator final : public CodeGenerator }; //----------------------------------------------------------------------------- +/// Transforms `break` and `continue` in the instantiations of a `template for` into `goto`. +class ExpansionStmtCodeGenerator final : public CodeGenerator +{ + std::string mLabelId{}; + size_t mIndex{}; + size_t mBreakCaptured{}; //!< Nesting depth of loops and switches capturing `break`. + size_t mContinueCaptured{}; //!< Nesting depth of loops capturing `continue`. + bool mBreakUsed{}; + bool mContinueUsed{}; //!< A `switch` has no `continue` + + std::string BreakLabel() const { return StrCat(BuildInternalVarName(kwBreak), mLabelId); } + std::string ContinueLabel() const { return StrCat(BuildInternalVarName(kwContinue), mLabelId, "_"sv, mIndex); } + + void InsertCapturing(const Stmt* stmt, bool capturesContinue) + { + ++mBreakCaptured; + if(capturesContinue) { + ++mContinueCaptured; + } + + CodeGenerator::InsertArg(stmt); + + --mBreakCaptured; + if(capturesContinue) { + --mContinueCaptured; + } + } + +public: + ExpansionStmtCodeGenerator(const CXXExpansionStmtDecl* decl, + OutputFormatHelper& outputFormatHelper, + LambdaStackType& lambdaStack) + : CodeGenerator{outputFormatHelper, lambdaStack, ProcessingPrimaryTemplate::No} + , mLabelId{MakeLineColumnName(GetSM(*decl), decl->getBeginLoc(), "_"sv)} + { + } + + using CodeGenerator::InsertArg; + + void InsertInstantiations(const CXXExpansionStmtInstantiation& inst) + { + for(const auto& e : inst.getPreambleStmts()) { + InsertArg(e); + } + + for(const auto e : inst.getInstantiations()) { + mContinueUsed = false; + + InsertArg(e); + mOutputFormatHelper.AppendNewLine(); + + if(mContinueUsed) { + mOutputFormatHelper.AppendNewLine(ContinueLabel(), ":"sv); + } + + ++mIndex; + } + + if(mBreakUsed) { + mOutputFormatHelper.AppendNewLine(BreakLabel(), ":"sv); + } + } + + void InsertArg(const BreakStmt* stmt) override + { + if(mBreakCaptured) { + CodeGenerator::InsertArg(stmt); + } else { + mBreakUsed = true; + mOutputFormatHelper.Append(kwGotoSpace, BreakLabel()); + } + } + + void InsertArg(const ContinueStmt* stmt) override + { + if(mContinueCaptured) { + CodeGenerator::InsertArg(stmt); + } else { + mContinueUsed = true; + mOutputFormatHelper.Append(kwGotoSpace, ContinueLabel()); + } + } + + void InsertArg(const ForStmt* stmt) override { InsertCapturing(stmt, true); } + void InsertArg(const CXXForRangeStmt* stmt) override { InsertCapturing(stmt, true); } + void InsertArg(const WhileStmt* stmt) override { InsertCapturing(stmt, true); } + void InsertArg(const DoStmt* stmt) override { InsertCapturing(stmt, true); } + void InsertArg(const SwitchStmt* stmt) override { InsertCapturing(stmt, false); } +}; +//----------------------------------------------------------------------------- + CodeGenerator::LambdaScopeHandler::LambdaScopeHandler(LambdaStackType& stack, OutputFormatHelper& outputFormatHelper, const LambdaCallerType lambdaCallerType) @@ -825,7 +916,8 @@ static std::string_view GetStorageClassAsString(const StorageClass& sc) static std::string GetStorageClassAsStringWithSpace(const StorageClass& sc) { - std::string ret{GetStorageClassAsString(sc)}; + // `auto` as a storage class specifier is not valid C++. Expansion statements synthesize such declarations. + std::string ret{SC_Auto == sc ? ""sv : GetStorageClassAsString(sc)}; if(not ret.empty()) { ret.append(" "sv); @@ -945,11 +1037,11 @@ class TemporaryDeclFinder : public StmtVisitor // XXX hack. Our normal VarDecl is at TU level. It then appears in cxa_start... auto& ctx = GetGlobalAST(); auto* vd = ImplicitParamDecl::Create(const_cast(ctx), - ctx.getTranslationUnitDecl(), + ctx.getTranslationUnitDecl(), {}, - &ctx.Idents.get(mTempName), - expr->getType(), - ImplicitParamKind::Other); + &ctx.Idents.get(mTempName), + expr->getType(), + ImplicitParamKind::Other); #endif @@ -1425,7 +1517,11 @@ void CodeGenerator::InsertArg(const VarDecl* stmt) IsPrimaryTemplatePackExpansionExpr(dyn_cast_or_null(init))}; if(not isa(init) and not isPrimaryTemplatePackExpansionExpr) { - mOutputFormatHelper.Append(hlpAssing); + if(ReplaceAssignWithColon::No == mReplaceAssignWithColon) { + mOutputFormatHelper.Append(hlpAssing); + } else { + mOutputFormatHelper.Append(" : "); + } } WrapInParensIfNeeded(isPrimaryTemplatePackExpansionExpr, [&] { @@ -2085,6 +2181,52 @@ void CodeGenerator::InsertArg(const CXXFoldExpr* stmt) } //----------------------------------------------------------------------------- +void CodeGenerator::InsertArg(const CXXExpansionSelectExpr* stmt) +{ + InsertArg(stmt->getRangeExpr()); +} +//----------------------------------------------------------------------------- + +void CodeGenerator::InsertArg(const CXXExpansionStmtDecl* stmt) +{ + if(const auto* inst = stmt->getInstantiations()) { + mOutputFormatHelper.OpenScope(); + + ExpansionStmtCodeGenerator codeGenerator{stmt, mOutputFormatHelper, mLambdaStack}; + codeGenerator.InsertInstantiations(*inst); + + mOutputFormatHelper.CloseScope(); + + } else if(const auto* pattern = stmt->getExpansionPattern()) { + mOutputFormatHelper.Append(kwTemplate, " for"sv); + + WrapInParens([&] { + if(const auto* init = pattern->getInit()) { + MultiStmtDeclCodeGenerator codeGenerator{mOutputFormatHelper, mLambdaStack, true}; + codeGenerator.InsertArg(init); + } + + MultiStmtDeclCodeGenerator codeGenerator{ + mOutputFormatHelper, mLambdaStack, MultiStmtDeclCodeGenerator::SkipFinalSemi::Yes}; + + { + BackupAndRestore _{codeGenerator.mReplaceAssignWithColon, ReplaceAssignWithColon::Yes}; + codeGenerator.InsertArg(pattern->getExpansionVarStmt()); + } + + if(pattern->isDependent()) { + mOutputFormatHelper.Append(" : "sv); + InsertArg(pattern->getExpansionInitializer()); + } + }); + + InsertArg(pattern->getBody()); + } + + mOutputFormatHelper.AppendNewLine(); +} +//----------------------------------------------------------------------------- + void CodeGenerator::InsertArg(const PackIndexingExpr* stmt) { if(stmt->isFullySubstituted()) { @@ -2498,9 +2640,12 @@ void CodeGenerator::HandleCompoundStmt(const CompoundStmt* stmt) CXXForRangeStmt, SwitchStmt, CXXTryStmt, + CompoundStmt, CppInsightsCommentStmt>(item) and InsertSemi() and not skipSemiForLambda and not mSkipSemi) { mOutputFormatHelper.AppendSemiNewLine(); + } else if(isa(item)) { + mOutputFormatHelper.AppendNewLine(); } mSkipSemi = false; @@ -4306,7 +4451,7 @@ void CodeGenerator::FormatCast(const std::string_view castName, const CastKind& castKind) { const bool isCastToBase{is{castKind}.any_of(CK_DerivedToBase, CK_UncheckedDerivedToBase) and - castDestType->isRecordType()}; + castDestType->isRecordType()}; const std::string castDestTypeText{ StrCat(GetName(castDestType), ((isCastToBase and not castDestType->isAnyPointerType()) ? "&"sv : ""sv))}; @@ -4724,7 +4869,7 @@ void CodeGenerator::InsertFunctionNameWithReturnType(const FunctionDecl& d bool isCXXMethodDecl{nullptr != methodDecl}; const bool isClassTemplateSpec{isCXXMethodDecl and isa(methodDecl->getParent())}; const bool requiresComment{isCXXMethodDecl and not methodDecl->isUserProvided() and - not methodDecl->isExplicitlyDefaulted()}; + not methodDecl->isExplicitlyDefaulted()}; // [expr.prim.lambda.closure] p7 consteval/constexpr are obtained from the call operator const bool isLambdaStaticInvoker{isCXXMethodDecl and methodDecl->isLambdaStaticInvoker()}; const auto desugaredReturnType = GetType(GetDesugarReturnType(decl)); diff --git a/CodeGenerator.h b/CodeGenerator.h index 63bbeff2..e210b315 100644 --- a/CodeGenerator.h +++ b/CodeGenerator.h @@ -412,6 +412,7 @@ class CodeGenerator STRONG_BOOL(UseCommaInsteadOfSemi); STRONG_BOOL(NoEmptyInitList); STRONG_BOOL(ShowConstantExprValue); + STRONG_BOOL(ReplaceAssignWithColon); ShowConstantExprValue mShowConstantExprValue{ShowConstantExprValue::No}; SkipVarDecl mSkipVarDecl{SkipVarDecl::No}; @@ -430,11 +431,12 @@ class CodeGenerator //!< potential std::initializer_list expansion must be inserted. std::optional mCurrentFieldPos{}; //!< The position in mOutputFormatHelper in a class where where a //!< potential std::initializer_list expansion must be inserted. - OutputFormatHelper* mOutputFormatHelperOutside{ + OutputFormatHelper* mOutputFormatHelperOutside{ nullptr}; //!< Helper output buffer for std::initializer_list expansion. bool mRequiresImplicitReturnZero{}; //!< Track whether this is a function with an imlpicit return 0. bool mSkipSemi{}; ProcessingPrimaryTemplate mProcessingPrimaryTemplate{}; + ReplaceAssignWithColon mReplaceAssignWithColon{}; //!< Special case for `for template`. static inline std::map mSeenDecls{}; }; //----------------------------------------------------------------------------- @@ -460,15 +462,33 @@ class MultiStmtDeclCodeGenerator final : public CodeGenerator { } + STRONG_BOOL(SkipFinalSemi); + + explicit MultiStmtDeclCodeGenerator(OutputFormatHelper& _outputFormatHelper, + LambdaStackType& lambdaStack, + SkipFinalSemi skipFinalSemi) + : CodeGenerator{_outputFormatHelper, lambdaStack, ProcessingPrimaryTemplate::No} + , mInsertVarDecl{true} + , mInsertComma{} + , mSkipFinalSemi{skipFinalSemi} + { + } + // Insert the semi after the last declaration. This implies that this class always requires its own scope. - ~MultiStmtDeclCodeGenerator() { mOutputFormatHelper.Append("; "sv); } + ~MultiStmtDeclCodeGenerator() + { + if(SkipFinalSemi::No == mSkipFinalSemi) { + mOutputFormatHelper.Append("; "sv); + } + } using CodeGenerator::InsertArg; protected: - OnceTrue mInsertVarDecl{}; //! Insert the \c VarDecl only once. - OnceFalse mInsertComma{}; //! Insert the comma after we have generated the first \c VarDecl and we are about to - //! insert another one. + OnceTrue mInsertVarDecl{}; //! Insert the \c VarDecl only once. + OnceFalse mInsertComma{}; //! Insert the comma after we have generated the first \c VarDecl and we are about to + //! insert another one. + SkipFinalSemi mSkipFinalSemi{SkipFinalSemi::No}; //! Skip inserting the semi colon once the object gets destroyed. bool InsertVarDecl(const VarDecl*) override { return mInsertVarDecl; } bool InsertComma() override { return mInsertComma; } diff --git a/CodeGeneratorTypes.h b/CodeGeneratorTypes.h index e5c120be..6fc7f9b0 100644 --- a/CodeGeneratorTypes.h +++ b/CodeGeneratorTypes.h @@ -50,6 +50,7 @@ SUPPORTED_DECL(VarTemplateDecl) SUPPORTED_DECL(ConceptDecl) SUPPORTED_DECL(UnresolvedUsingValueDecl) SUPPORTED_DECL(LinkageSpecDecl) +SUPPORTED_DECL(CXXExpansionStmtDecl) SUPPORTED_STMT(CXXDeleteExpr) SUPPORTED_STMT(CXXDefaultInitExpr) @@ -140,6 +141,7 @@ SUPPORTED_STMT(CXXParenListInitExpr) SUPPORTED_STMT(CppInsightsCommentStmt) SUPPORTED_STMT(CXXPseudoDestructorExpr) SUPPORTED_STMT(PackIndexingExpr) +SUPPORTED_STMT(CXXExpansionSelectExpr) #undef IGNORED_DECL #undef IGNORED_STMT diff --git a/InsightsHelpers.cpp b/InsightsHelpers.cpp index fc63f82f..04da8635 100644 --- a/InsightsHelpers.cpp +++ b/InsightsHelpers.cpp @@ -486,10 +486,10 @@ class SimpleTypePrinter std::string mDataAfter{}; bool mHasData{false}; bool mSkipSpace{false}; - bool mScanningArrayDimension{}; //!< Only the outer most ConstantArrayType handles the array dimensions and size - std::string mScope{}; //!< A scope coming from an ElaboratedType which is used for a - //!< ClassTemplateSpecializationDecl if there is no other scope - bool mTmplParamTypeRes{}; //!< When processing FunctionProtoType parameters we need to get the identifiers + bool mScanningArrayDimension{}; //!< Only the outer most ConstantArrayType handles the array dimensions and size + std::string mScope{}; //!< A scope coming from an ElaboratedType which is used for a + //!< ClassTemplateSpecializationDecl if there is no other scope + bool mTmplParamTypeRes{}; //!< When processing FunctionProtoType parameters we need to get the identifiers bool HandleType(const TemplateTypeParmType* type) { diff --git a/tests/Issue540.expect b/tests/Issue540.expect index 39b8a110..b4ac6509 100644 --- a/tests/Issue540.expect +++ b/tests/Issue540.expect @@ -10,7 +10,7 @@ int main() { int a = 5; std::cout.operator<<(a + (::a)); - }; - }; + } + } return 0; } diff --git a/tests/StructuredBindingsHandler3Test.expect b/tests/StructuredBindingsHandler3Test.expect index 2c5eea1d..36eeff9c 100644 --- a/tests/StructuredBindingsHandler3Test.expect +++ b/tests/StructuredBindingsHandler3Test.expect @@ -122,7 +122,7 @@ namespace constant int && b = get<1UL>(static_cast(__q26)); int && c = get<2UL>(static_cast(__q26)); p = &c; - }; + } return *p; } diff --git a/tests/p1306Test.cpp b/tests/p1306Test.cpp new file mode 100644 index 00000000..5e3e7619 --- /dev/null +++ b/tests/p1306Test.cpp @@ -0,0 +1,10 @@ +// cmdline:-std=c++26 + +int main() +{ + int res{}; + template for(auto x : {1, 2, 3}) + { + res += x; + } +} diff --git a/tests/p1306Test.expect b/tests/p1306Test.expect new file mode 100644 index 00000000..36354bff --- /dev/null +++ b/tests/p1306Test.expect @@ -0,0 +1,26 @@ +int main() +{ + int res = {}; + { + { + int x = 1; + { + res = res + x; + } + } + { + int x = 2; + { + res = res + x; + } + } + { + int x = 3; + { + res = res + x; + } + } + + } + return 0; +} diff --git a/tests/p1306Test_2.cpp b/tests/p1306Test_2.cpp new file mode 100644 index 00000000..490970a9 --- /dev/null +++ b/tests/p1306Test_2.cpp @@ -0,0 +1,25 @@ +// cmdline:-std=c++26 + +#define INSIGHTS_USE_TEMPLATE 1 + +template +constexpr T min(const T& x, + const T& y, + const Args&... vals) // #B Parameter pack +{ + auto m = x < y ? x : y; + + template for(int init{3}; const auto& e : {vals...}) + { + if(e < m) { m = e; } + } + + return m; +} + +static_assert(min(3, 2) == 2); +static_assert(min(3, 2, 3, 4, 5) == 2); + +int main() {} diff --git a/tests/p1306Test_2.expect b/tests/p1306Test_2.expect new file mode 100644 index 00000000..bb3be6c1 --- /dev/null +++ b/tests/p1306Test_2.expect @@ -0,0 +1,79 @@ +#define INSIGHTS_USE_TEMPLATE + +template +inline constexpr T min(const T & x, const T & y, const Args &... vals) +{ + auto m = x < y ? x : y /* NRVO variable */; + template for(int init = {3}; const auto & e : {vals... }){ + if(e < m) { + m = e; + } + + } + return m; +} + +/* First instantiated from: p1306Test_2.cpp:22 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +inline constexpr int min(const int & x, const int & y) +{ + int m = x < y ? x : y; + { + int init = {3}; + + } + return static_cast(m); +} +#endif + + +/* First instantiated from: p1306Test_2.cpp:23 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +inline constexpr int min(const int & x, const int & y, const int & __vals2, const int & __vals3, const int & __vals4) +{ + int m = x < y ? x : y; + { + int init = {3}; + { + int const & e = __vals2; + { + if(e < m) { + m = e; + } + + } + } + { + int const & e = __vals3; + { + if(e < m) { + m = e; + } + + } + } + { + int const & e = __vals4; + { + if(e < m) { + m = e; + } + + } + } + + } + return static_cast(m); +} +#endif + + +/* PASSED: static_assert(min(3, 2) == 2); */ +/* PASSED: static_assert(min(3, 2, 3, 4, 5) == 2); */ + +int main() +{ + return 0; +} diff --git a/tests/p1306Test_3.cpp b/tests/p1306Test_3.cpp new file mode 100644 index 00000000..28dccd73 --- /dev/null +++ b/tests/p1306Test_3.cpp @@ -0,0 +1,24 @@ +// cmdline:-std=c++26 + +#define INSIGHTS_USE_TEMPLATE 1 + +#include + +template +void Call(const T&) +{} + +template +void Fun() +{ + std::tuple tpl{1, 2l, 3u}; + template for(int idx{}; auto x : tpl) + { + Call(x); + } +} + +int main() +{ + Fun(); +} diff --git a/tests/p1306Test_3.expect b/tests/p1306Test_3.expect new file mode 100644 index 00000000..d1ea5733 --- /dev/null +++ b/tests/p1306Test_3.expect @@ -0,0 +1,86 @@ +#define INSIGHTS_USE_TEMPLATE + +#include + +template +void Call(const T &) +{ +} + +/* First instantiated from: p1306Test_3.cpp:17 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +void Call(const int &) +{ +} +#endif + + +/* First instantiated from: p1306Test_3.cpp:17 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +void Call(const long &) +{ +} +#endif + + +/* First instantiated from: p1306Test_3.cpp:17 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +void Call(const unsigned int &) +{ +} +#endif + + +template +void Fun() +{ + std::tuple tpl = {1, 2L, 3U}; + template for(int idx = {}; auto x : tpl){ + Call(x); + } +} + +/* First instantiated from: p1306Test_3.cpp:23 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +void Fun() +{ + std::tuple tpl = std::tuple{1, 2L, 3U}; + { + int idx = {}; + std::tuple & __tpl15 = tpl; + int & __u0 = std::get<0UL>(__tpl15); + long & __u1 = std::get<1UL>(__tpl15); + unsigned int & __u2 = std::get<2UL>(__tpl15); + { + int x = __u0; + { + Call(x); + } + } + { + long x = __u1; + { + Call(x); + } + } + { + unsigned int x = __u2; + { + Call(x); + } + } + + } +} +#endif + + +int main() +{ + Fun(); + return 0; +} diff --git a/tests/p1306Test_4.cpp b/tests/p1306Test_4.cpp new file mode 100644 index 00000000..beabd6c6 --- /dev/null +++ b/tests/p1306Test_4.cpp @@ -0,0 +1,12 @@ +// cmdline:-std=c++26 + +#include + +int main() +{ + static constexpr std::string_view foo = "abcd"; + template for(auto x : foo) + { + // ... + } +} diff --git a/tests/p1306Test_4.expect b/tests/p1306Test_4.expect new file mode 100644 index 00000000..1ef415d4 --- /dev/null +++ b/tests/p1306Test_4.expect @@ -0,0 +1,7 @@ +#include + +int main() +{ + static constexpr const std::basic_string_view > foo = std::basic_string_view >("abcd"); + return 0; +} diff --git a/tests/p1306Test_4.ignore b/tests/p1306Test_4.ignore new file mode 100644 index 00000000..e69de29b diff --git a/tests/p1306Test_5.cpp b/tests/p1306Test_5.cpp new file mode 100644 index 00000000..a44ae110 --- /dev/null +++ b/tests/p1306Test_5.cpp @@ -0,0 +1,29 @@ +// cmdline:-std=c++26 + +#define INSIGHTS_USE_TEMPLATE 1 + +#include + +int main() +{ + std::tuple tpl{1, 'a', 3l}; + int arr[]{4, 5, 6}; + int res{}; + + template for(auto& e : tpl) + { + res += static_cast(e); + } + + template for(const auto& e : arr) + { + res += e; + } + + template for(auto x : {1, 2, 3}) + { + template for(auto y : {10, 20}) { res += x * y; } + } + + return res; +} diff --git a/tests/p1306Test_5.expect b/tests/p1306Test_5.expect new file mode 100644 index 00000000..50892783 --- /dev/null +++ b/tests/p1306Test_5.expect @@ -0,0 +1,124 @@ +#define INSIGHTS_USE_TEMPLATE + +#include + +int main() +{ + std::tuple tpl = std::tuple{1, 'a', 3L}; + int arr[3] = {4, 5, 6}; + int res = {}; + { + std::tuple & __tpl13 = tpl; + int & __u0 = std::get<0UL>(__tpl13); + char & __u1 = std::get<1UL>(__tpl13); + long & __u2 = std::get<2UL>(__tpl13); + { + std::tuple_element<0, std::tuple >::type & e = __u0; + { + res = res + static_cast(e); + } + } + { + std::tuple_element<1, std::tuple >::type & e = __u1; + { + res = res + static_cast(e); + } + } + { + std::tuple_element<2, std::tuple >::type & e = __u2; + { + res = res + static_cast(e); + } + } + + } + { + int (&__arr18)[3] = arr; + int & __u0 = __arr18[0]; + int & __u1 = __arr18[1]; + int & __u2 = __arr18[2]; + { + const int & e = __u0; + { + res = res + e; + } + } + { + const int & e = __u1; + { + res = res + e; + } + } + { + const int & e = __u2; + { + res = res + e; + } + } + + } + { + { + int x = 1; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + { + int x = 2; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + { + int x = 3; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + + } + return static_cast(res); +} diff --git a/tests/p1306Test_6.cpp b/tests/p1306Test_6.cpp new file mode 100644 index 00000000..632d8c3c --- /dev/null +++ b/tests/p1306Test_6.cpp @@ -0,0 +1,60 @@ +// cmdline:-std=c++26 + +#define INSIGHTS_USE_TEMPLATE 1 + +#include + +struct Point +{ + int x; + char y; +}; + +template +int Sum(T& range) +{ + int sum{}; + + template for(auto& e : range) + { + sum += static_cast(e); + } + + return sum; +} + +int main() +{ + std::tuple tpl{1, 'a', 3l}; + int arr[]{4, 5, 6}; + Point pt{7, 'b'}; + std::tuple<> empty{}; + int res{}; + + template for(auto& e : tpl) + { + res += static_cast(e); + } + + template for(const auto& e : arr) + { + res += e; + } + + template for(auto& e : pt) + { + res += static_cast(e); + } + + template for(auto& e : empty) + { + res += static_cast(e); + } + + template for(auto x : {1, 2, 3}) + { + template for(auto y : {10, 20}) { res += x * y; } + } + + return res + Sum(tpl) + Sum(arr); +} diff --git a/tests/p1306Test_6.expect b/tests/p1306Test_6.expect new file mode 100644 index 00000000..d509fbd8 --- /dev/null +++ b/tests/p1306Test_6.expect @@ -0,0 +1,237 @@ +#define INSIGHTS_USE_TEMPLATE + +#include + +struct Point +{ + int x; + char y; +}; + + +template +int Sum(T & range) +{ + int sum = {}; + template for(auto & e : range){ + sum = sum + static_cast(e); + } + return static_cast(sum); +} + +/* First instantiated from: p1306Test_6.cpp:59 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +int Sum >(std::tuple & range) +{ + int sum = {}; + { + std::tuple & __range18 = range; + int & __u0 = std::get<0UL>(__range18); + char & __u1 = std::get<1UL>(__range18); + long & __u2 = std::get<2UL>(__range18); + { + std::tuple_element<0, std::tuple >::type & e = __u0; + { + sum = sum + static_cast(e); + } + } + { + std::tuple_element<1, std::tuple >::type & e = __u1; + { + sum = sum + static_cast(e); + } + } + { + std::tuple_element<2, std::tuple >::type & e = __u2; + { + sum = sum + static_cast(e); + } + } + + } + return static_cast(sum); +} +#endif + + +/* First instantiated from: p1306Test_6.cpp:59 */ +#ifdef INSIGHTS_USE_TEMPLATE +template<> +int Sum(int (&range)[3]) +{ + int sum = {}; + { + int (&__range18)[3] = range; + int & __u0 = __range18[0]; + int & __u1 = __range18[1]; + int & __u2 = __range18[2]; + { + int & e = __u0; + { + sum = sum + static_cast(e); + } + } + { + int & e = __u1; + { + sum = sum + static_cast(e); + } + } + { + int & e = __u2; + { + sum = sum + static_cast(e); + } + } + + } + return static_cast(sum); +} +#endif + + +int main() +{ + std::tuple tpl = std::tuple{1, 'a', 3L}; + int arr[3] = {4, 5, 6}; + Point pt = {7, 'b'}; + std::tuple<> empty; + int res = {}; + { + std::tuple & __tpl34 = tpl; + int & __u0 = std::get<0UL>(__tpl34); + char & __u1 = std::get<1UL>(__tpl34); + long & __u2 = std::get<2UL>(__tpl34); + { + std::tuple_element<0, std::tuple >::type & e = __u0; + { + res = res + static_cast(e); + } + } + { + std::tuple_element<1, std::tuple >::type & e = __u1; + { + res = res + static_cast(e); + } + } + { + std::tuple_element<2, std::tuple >::type & e = __u2; + { + res = res + static_cast(e); + } + } + + } + { + int (&__arr39)[3] = arr; + int & __u0 = __arr39[0]; + int & __u1 = __arr39[1]; + int & __u2 = __arr39[2]; + { + const int & e = __u0; + { + res = res + e; + } + } + { + const int & e = __u1; + { + res = res + e; + } + } + { + const int & e = __u2; + { + res = res + e; + } + } + + } + { + Point & __pt44 = pt; + int & __u0 = __pt44.x; + char & __u1 = __pt44.y; + { + int & e = __u0; + { + res = res + static_cast(e); + } + } + { + char & e = __u1; + { + res = res + static_cast(e); + } + } + + } + { + std::tuple<> & __empty49 = empty; + + } + { + { + int x = 1; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + { + int x = 2; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + { + int x = 3; + { + { + { + int y = 10; + { + res = res + (x * y); + } + } + { + int y = 20; + { + res = res + (x * y); + } + } + + } + } + } + + } + return (res + Sum(tpl)) + Sum(arr); +} diff --git a/tests/p1306Test_7.cpp b/tests/p1306Test_7.cpp new file mode 100644 index 00000000..acee2443 --- /dev/null +++ b/tests/p1306Test_7.cpp @@ -0,0 +1,21 @@ +// cmdline:-std=c++26 + +#include + + +int main() +{ + int res{}; + template for(auto x : {1, 2, 3}) + { + res += x; + + if(x == 2) { continue; } + + if(x == 3) { break; } + + printf("%d\n", x); + } + + printf("end\n"); +} diff --git a/tests/p1306Test_7.expect b/tests/p1306Test_7.expect new file mode 100644 index 00000000..c0e3a555 --- /dev/null +++ b/tests/p1306Test_7.expect @@ -0,0 +1,60 @@ +#include + +int main() +{ + int res = {}; + { + { + int x = 1; + { + res = res + x; + if(x == 2) { + goto __continue_9_3_0; + } + + if(x == 3) { + goto __break_9_3; + } + + printf("%d\n", x); + } + } + __continue_9_3_0: + { + int x = 2; + { + res = res + x; + if(x == 2) { + goto __continue_9_3_1; + } + + if(x == 3) { + goto __break_9_3; + } + + printf("%d\n", x); + } + } + __continue_9_3_1: + { + int x = 3; + { + res = res + x; + if(x == 2) { + goto __continue_9_3_2; + } + + if(x == 3) { + goto __break_9_3; + } + + printf("%d\n", x); + } + } + __continue_9_3_2: + __break_9_3: + + } + printf("end\n"); + return 0; +}