@@ -364,7 +364,59 @@ bool Converter::VisitFunctionDecl(clang::FunctionDecl *decl) {
364364 return false ;
365365}
366366
367+ void Converter::EmitHoistedDecls (clang::CompoundStmt *body) {
368+ for (auto *child : body->body ()) {
369+ if (auto *decl_stmt = clang::dyn_cast<clang::DeclStmt>(child)) {
370+ for (auto *decl : decl_stmt->decls ()) {
371+ if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
372+ var && var->isLocalVarDecl () && !IsGlobalVar (var)) {
373+ hoisted_decls_.insert (var);
374+ if (ConvertVarDeclSkipInit (var)) {
375+ StrCat (token::kAssign , ConvertVarDefaultInit (var->getType ()),
376+ token::kSemiColon );
377+ }
378+ }
379+ }
380+ }
381+ }
382+ }
383+
384+ void Converter::ConvertGotoBlock (clang::CompoundStmt *body) {
385+ PushHoistedDecls push (hoisted_decls_);
386+ EmitHoistedDecls (body);
387+
388+ StrCat (" goto_block!" );
389+ {
390+ PushParen paren (*this );
391+ PushBrace outer (*this );
392+ StrCat (" '__entry: " );
393+ std::optional<PushBrace> arm;
394+ arm.emplace (*this );
395+ for (auto *child : body->body ()) {
396+ if (auto *label = clang::dyn_cast<clang::LabelStmt>(child)) {
397+ arm.reset ();
398+ StrCat (std::format (" '{}: " , label->getDecl ()->getName ().str ()));
399+ arm.emplace (*this );
400+ Convert (label->getSubStmt ());
401+ } else {
402+ Convert (child);
403+ }
404+ }
405+ }
406+ StrCat (token::kSemiColon );
407+ }
408+
367409void Converter::ConvertFunctionBody (clang::FunctionDecl *decl) {
410+ if (auto compound = clang::dyn_cast<clang::CompoundStmt>(decl->getBody ())) {
411+ if (CompoundHasTopLevelLabel (compound)) {
412+ ConvertGotoBlock (compound);
413+ if (!decl->getReturnType ()->isVoidType ()) {
414+ StrCat (R"( panic!("ub: non-void function does not return a value"))" );
415+ }
416+ return ;
417+ }
418+ }
419+
368420 Convert (decl->getBody ());
369421 if (!decl->getReturnType ()->isVoidType ()) {
370422 if (auto compound = clang::dyn_cast<clang::CompoundStmt>(decl->getBody ())) {
@@ -467,7 +519,20 @@ void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) {
467519 }
468520}
469521
522+ void Converter::EmitHoistedInArmAssignment (clang::VarDecl *decl) {
523+ if (!decl->hasInit ()) {
524+ return ;
525+ }
526+ StrCat (GetNamedDeclAsString (decl), token::kAssign );
527+ ConvertVarInit (decl->getType (), decl->getInit ());
528+ StrCat (token::kSemiColon );
529+ }
530+
470531void Converter::ConvertVarDecl (clang::VarDecl *decl) {
532+ if (hoisted_decls_.contains (decl)) {
533+ EmitHoistedInArmAssignment (decl);
534+ return ;
535+ }
471536 if (!ConvertVarDeclSkipInit (decl)) {
472537 // Skip global variables declared extern
473538 return ;
@@ -985,6 +1050,10 @@ bool Converter::Convert(clang::Stmt *stmt) {
9851050}
9861051
9871052bool Converter::VisitCompoundStmt (clang::CompoundStmt *stmt) {
1053+ if (CompoundHasTopLevelLabel (stmt)) {
1054+ ConvertGotoBlock (stmt);
1055+ return false ;
1056+ }
9881057 for (auto *child : stmt->body ()) {
9891058 Convert (child);
9901059 }
@@ -1011,6 +1080,11 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
10111080 return false ;
10121081}
10131082
1083+ bool Converter::VisitGotoStmt (clang::GotoStmt *stmt) {
1084+ StrCat (std::format (" goto!('{})" , stmt->getLabel ()->getName ().str ()));
1085+ return false ;
1086+ }
1087+
10141088void Converter::ConvertCondition (clang::Expr *cond) {
10151089 PushExprKind push (*this , ExprKind::RValue);
10161090 Convert (NormalizeToBool (cond, ctx_));
0 commit comments