@@ -363,7 +363,59 @@ bool Converter::VisitFunctionDecl(clang::FunctionDecl *decl) {
363363 return false ;
364364}
365365
366+ void Converter::EmitHoistedDecls (clang::CompoundStmt *body) {
367+ for (auto *child : body->body ()) {
368+ if (auto *decl_stmt = clang::dyn_cast<clang::DeclStmt>(child)) {
369+ for (auto *decl : decl_stmt->decls ()) {
370+ if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
371+ var && var->isLocalVarDecl () && !IsGlobalVar (var)) {
372+ hoisted_decls_.insert (var);
373+ if (ConvertVarDeclSkipInit (var)) {
374+ StrCat (token::kAssign , ConvertVarDefaultInit (var->getType ()),
375+ token::kSemiColon );
376+ }
377+ }
378+ }
379+ }
380+ }
381+ }
382+
383+ void Converter::ConvertGotoBlock (clang::CompoundStmt *body) {
384+ PushHoistedDecls push (hoisted_decls_);
385+ EmitHoistedDecls (body);
386+
387+ StrCat (" goto_block!" );
388+ {
389+ PushParen paren (*this );
390+ PushBrace outer (*this );
391+ StrCat (" '__entry: " );
392+ std::optional<PushBrace> arm;
393+ arm.emplace (*this );
394+ for (auto *child : body->body ()) {
395+ if (auto *label = clang::dyn_cast<clang::LabelStmt>(child)) {
396+ arm.reset ();
397+ StrCat (std::format (" '{}: " , label->getDecl ()->getName ().str ()));
398+ arm.emplace (*this );
399+ Convert (label->getSubStmt ());
400+ } else {
401+ Convert (child);
402+ }
403+ }
404+ }
405+ StrCat (token::kSemiColon );
406+ }
407+
366408void Converter::ConvertFunctionBody (clang::FunctionDecl *decl) {
409+ if (auto compound = clang::dyn_cast<clang::CompoundStmt>(decl->getBody ())) {
410+ if (CompoundHasTopLevelLabel (compound)) {
411+ ConvertGotoBlock (compound);
412+ if (!decl->getReturnType ()->isVoidType ()) {
413+ StrCat (R"( panic!("ub: non-void function does not return a value"))" );
414+ }
415+ return ;
416+ }
417+ }
418+
367419 Convert (decl->getBody ());
368420 if (!decl->getReturnType ()->isVoidType ()) {
369421 if (auto compound = clang::dyn_cast<clang::CompoundStmt>(decl->getBody ())) {
@@ -421,9 +473,11 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
421473 auto *method_or_null =
422474 curr_function_ ? clang::dyn_cast<clang::CXXMethodDecl>(curr_function_)
423475 : nullptr ;
424- if (!qual_type.isConstQualified () && !qual_type->isReferenceType () &&
425- ((method_or_null == nullptr ) || !method_or_null->isVirtual ()) &&
426- !IsGlobalVar (decl)) {
476+ if (hoisted_decls_.contains (decl) && !qual_type->isReferenceType ()) {
477+ StrCat (" mut" );
478+ } else if (!qual_type.isConstQualified () && !qual_type->isReferenceType () &&
479+ ((method_or_null == nullptr ) || !method_or_null->isVirtual ()) &&
480+ !IsGlobalVar (decl)) {
427481 StrCat (keyword_mut_);
428482 }
429483
@@ -467,6 +521,14 @@ void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) {
467521}
468522
469523void Converter::ConvertVarDecl (clang::VarDecl *decl) {
524+ if (hoisted_decls_.contains (decl)) {
525+ if (decl->hasInit ()) {
526+ StrCat (GetNamedDeclAsString (decl), token::kAssign );
527+ ConvertVarInit (decl->getType (), decl->getInit ());
528+ StrCat (token::kSemiColon );
529+ }
530+ return ;
531+ }
470532 if (!ConvertVarDeclSkipInit (decl)) {
471533 // Skip global variables declared extern
472534 return ;
@@ -984,6 +1046,10 @@ bool Converter::Convert(clang::Stmt *stmt) {
9841046}
9851047
9861048bool Converter::VisitCompoundStmt (clang::CompoundStmt *stmt) {
1049+ if (CompoundHasTopLevelLabel (stmt)) {
1050+ ConvertGotoBlock (stmt);
1051+ return false ;
1052+ }
9871053 for (auto *child : stmt->body ()) {
9881054 Convert (child);
9891055 }
@@ -1010,6 +1076,11 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
10101076 return false ;
10111077}
10121078
1079+ bool Converter::VisitGotoStmt (clang::GotoStmt *stmt) {
1080+ StrCat (std::format (" goto!('{})" , stmt->getLabel ()->getName ().str ()));
1081+ return false ;
1082+ }
1083+
10131084void Converter::ConvertCondition (clang::Expr *cond) {
10141085 PushExprKind push (*this , ExprKind::RValue);
10151086 Convert (NormalizeToBool (cond, ctx_));
0 commit comments