@@ -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 ())) {
@@ -466,7 +518,20 @@ void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) {
466518 }
467519}
468520
521+ void Converter::EmitHoistedInArmAssignment (clang::VarDecl *decl) {
522+ if (!decl->hasInit ()) {
523+ return ;
524+ }
525+ StrCat (GetNamedDeclAsString (decl), token::kAssign );
526+ ConvertVarInit (decl->getType (), decl->getInit ());
527+ StrCat (token::kSemiColon );
528+ }
529+
469530void Converter::ConvertVarDecl (clang::VarDecl *decl) {
531+ if (hoisted_decls_.contains (decl)) {
532+ EmitHoistedInArmAssignment (decl);
533+ return ;
534+ }
470535 if (!ConvertVarDeclSkipInit (decl)) {
471536 // Skip global variables declared extern
472537 return ;
@@ -984,6 +1049,10 @@ bool Converter::Convert(clang::Stmt *stmt) {
9841049}
9851050
9861051bool Converter::VisitCompoundStmt (clang::CompoundStmt *stmt) {
1052+ if (CompoundHasTopLevelLabel (stmt)) {
1053+ ConvertGotoBlock (stmt);
1054+ return false ;
1055+ }
9871056 for (auto *child : stmt->body ()) {
9881057 Convert (child);
9891058 }
@@ -1010,6 +1079,11 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
10101079 return false ;
10111080}
10121081
1082+ bool Converter::VisitGotoStmt (clang::GotoStmt *stmt) {
1083+ StrCat (std::format (" goto!('{})" , stmt->getLabel ()->getName ().str ()));
1084+ return false ;
1085+ }
1086+
10131087void Converter::ConvertCondition (clang::Expr *cond) {
10141088 PushExprKind push (*this , ExprKind::RValue);
10151089 Convert (NormalizeToBool (cond, ctx_));
0 commit comments