statements.rs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. // SPDX-License-Identifier: Apache-2.0
  2. use num_bigint::BigInt;
  3. use super::encoding::{abi_decode, abi_encode};
  4. use super::expression::{
  5. assert_failure, assign_single, default_gas, emit_function_call, expression, log_runtime_error,
  6. };
  7. use super::Options;
  8. use super::{
  9. cfg::{ControlFlowGraph, Instr},
  10. vartable::Vartable,
  11. };
  12. use crate::codegen::constructor::call_constructor;
  13. use crate::codegen::events::new_event_emitter;
  14. use crate::codegen::unused_variable::{
  15. should_remove_assignment, should_remove_variable, SideEffectsCheckParameters,
  16. };
  17. use crate::codegen::yul::inline_assembly_cfg;
  18. use crate::codegen::Expression;
  19. use crate::sema::Recurse;
  20. use crate::sema::{
  21. ast::{
  22. self, ArrayLength, CallTy, DestructureField, FormatArg, Function, Namespace, RetrieveType,
  23. Statement, TryCatch, Type, Type::Uint,
  24. },
  25. file::PathDisplay,
  26. };
  27. use num_traits::Zero;
  28. use solang_parser::pt::{self, CodeLocation, Loc::Codegen};
  29. /// Resolve a statement, which might be a block of statements or an entire body of a function
  30. pub(crate) fn statement(
  31. stmt: &Statement,
  32. func: &Function,
  33. cfg: &mut ControlFlowGraph,
  34. contract_no: usize,
  35. ns: &Namespace,
  36. vartab: &mut Vartable,
  37. loops: &mut LoopScopes,
  38. placeholder: Option<&Instr>,
  39. return_override: Option<&Instr>,
  40. opt: &Options,
  41. ) {
  42. match stmt {
  43. Statement::Block { statements, .. } => {
  44. for stmt in statements {
  45. statement(
  46. stmt,
  47. func,
  48. cfg,
  49. contract_no,
  50. ns,
  51. vartab,
  52. loops,
  53. placeholder,
  54. return_override,
  55. opt,
  56. );
  57. }
  58. }
  59. Statement::VariableDecl(loc, pos, _, Some(init)) => {
  60. if should_remove_variable(*pos, func, opt) {
  61. let mut params = SideEffectsCheckParameters {
  62. cfg,
  63. contract_no,
  64. func: Some(func),
  65. ns,
  66. vartab,
  67. opt,
  68. };
  69. //If we remove the assignment, we must keep expressions that have side effects
  70. init.recurse(&mut params, process_side_effects_expressions);
  71. return;
  72. }
  73. let mut expression = expression(init, cfg, contract_no, Some(func), ns, vartab, opt);
  74. // Let's check if the declaration is a declaration of a dynamic array
  75. if let Expression::AllocDynamicBytes {
  76. loc: loc_dyn_arr,
  77. ty: ty_dyn_arr @ Type::Array(..),
  78. size,
  79. initializer: opt,
  80. } = expression
  81. {
  82. let temp_res = vartab.temp_name("array_length", &Uint(32));
  83. cfg.add(
  84. vartab,
  85. Instr::Set {
  86. loc: *loc,
  87. res: temp_res,
  88. expr: *size,
  89. },
  90. );
  91. // If expression is an AllocDynamic array, replace the expression with AllocDynamicArray(_,_,tempvar,_) to avoid inserting size twice in the cfg
  92. expression = Expression::AllocDynamicBytes {
  93. loc: loc_dyn_arr,
  94. ty: ty_dyn_arr,
  95. size: Box::new(Expression::Variable {
  96. loc: *loc,
  97. ty: Uint(32),
  98. var_no: temp_res,
  99. }),
  100. initializer: opt,
  101. };
  102. cfg.array_lengths_temps.insert(*pos, temp_res);
  103. } else if let Expression::Variable { var_no, .. } = &expression {
  104. // If declaration happens with an existing array, check if the size of the array is known.
  105. // If the size of the right hand side is known (is in the array_length_map), make the left hand side track it
  106. // Now, we will have two keys in the map that point to the same temporary variable
  107. if let Some(to_add) = cfg.array_lengths_temps.clone().get(var_no) {
  108. cfg.array_lengths_temps.insert(*pos, *to_add);
  109. }
  110. }
  111. cfg.add(
  112. vartab,
  113. Instr::Set {
  114. loc: *loc,
  115. res: *pos,
  116. expr: expression,
  117. },
  118. );
  119. }
  120. Statement::VariableDecl(loc, pos, param, None) => {
  121. if should_remove_variable(*pos, func, opt) {
  122. return;
  123. }
  124. // Add variable as undefined
  125. cfg.add(
  126. vartab,
  127. Instr::Set {
  128. loc: *loc,
  129. res: *pos,
  130. expr: Expression::Undefined {
  131. ty: param.ty.clone(),
  132. },
  133. },
  134. );
  135. // Handling arrays without size, defaulting the initial size with zero
  136. if matches!(param.ty, Type::Array(..)) {
  137. let num = Expression::NumberLiteral {
  138. loc: Codegen,
  139. ty: Uint(32),
  140. value: BigInt::zero(),
  141. };
  142. let temp_res = vartab.temp_name("array_length", &Uint(32));
  143. cfg.add(
  144. vartab,
  145. Instr::Set {
  146. loc: *loc,
  147. res: temp_res,
  148. expr: num,
  149. },
  150. );
  151. cfg.array_lengths_temps.insert(*pos, temp_res);
  152. }
  153. }
  154. Statement::Return(_, expr) => {
  155. if let Some(return_instr) = return_override {
  156. cfg.add(vartab, return_instr.clone());
  157. } else {
  158. match expr {
  159. None => cfg.add(vartab, Instr::Return { value: Vec::new() }),
  160. Some(expr) => returns(expr, cfg, contract_no, func, ns, vartab, opt),
  161. }
  162. }
  163. }
  164. Statement::Expression(_, _, expr) => {
  165. if let ast::Expression::Assign { left, right, .. } = &expr {
  166. if should_remove_assignment(ns, left, func, opt) {
  167. let mut params = SideEffectsCheckParameters {
  168. cfg,
  169. contract_no,
  170. func: Some(func),
  171. ns,
  172. vartab,
  173. opt,
  174. };
  175. right.recurse(&mut params, process_side_effects_expressions);
  176. return;
  177. }
  178. } else if let ast::Expression::Builtin { args, .. } = expr {
  179. // When array pop and push are top-level expressions, they can be removed
  180. if should_remove_assignment(ns, expr, func, opt) {
  181. let mut params = SideEffectsCheckParameters {
  182. cfg,
  183. contract_no,
  184. func: Some(func),
  185. ns,
  186. vartab,
  187. opt,
  188. };
  189. for arg in args {
  190. arg.recurse(&mut params, process_side_effects_expressions);
  191. }
  192. return;
  193. }
  194. }
  195. let _ = expression(expr, cfg, contract_no, Some(func), ns, vartab, opt);
  196. }
  197. Statement::Delete(_, ty, expr) => {
  198. let var_expr = expression(expr, cfg, contract_no, Some(func), ns, vartab, opt);
  199. cfg.add(
  200. vartab,
  201. Instr::ClearStorage {
  202. ty: ty.clone(),
  203. storage: var_expr,
  204. },
  205. );
  206. }
  207. Statement::Break(_) => {
  208. cfg.add(
  209. vartab,
  210. Instr::Branch {
  211. block: loops.do_break(),
  212. },
  213. );
  214. }
  215. Statement::Continue(_) => {
  216. cfg.add(
  217. vartab,
  218. Instr::Branch {
  219. block: loops.do_continue(),
  220. },
  221. );
  222. }
  223. Statement::If(_, _, cond, then_stmt, else_stmt) if else_stmt.is_empty() => {
  224. if_then(
  225. cond,
  226. then_stmt,
  227. func,
  228. cfg,
  229. contract_no,
  230. ns,
  231. vartab,
  232. loops,
  233. placeholder,
  234. return_override,
  235. opt,
  236. );
  237. }
  238. Statement::If(_, _, cond, then_stmt, else_stmt) => if_then_else(
  239. cond,
  240. then_stmt,
  241. else_stmt,
  242. func,
  243. cfg,
  244. contract_no,
  245. ns,
  246. vartab,
  247. loops,
  248. placeholder,
  249. return_override,
  250. opt,
  251. ),
  252. Statement::DoWhile(_, _, body_stmt, cond_expr) => {
  253. let body = cfg.new_basic_block("body".to_string());
  254. let cond = cfg.new_basic_block("conf".to_string());
  255. let end = cfg.new_basic_block("enddowhile".to_string());
  256. cfg.add(vartab, Instr::Branch { block: body });
  257. cfg.set_basic_block(body);
  258. vartab.new_dirty_tracker();
  259. loops.new_scope(end, cond);
  260. let mut body_reachable = true;
  261. for stmt in body_stmt {
  262. statement(
  263. stmt,
  264. func,
  265. cfg,
  266. contract_no,
  267. ns,
  268. vartab,
  269. loops,
  270. placeholder,
  271. return_override,
  272. opt,
  273. );
  274. body_reachable = stmt.reachable();
  275. }
  276. if body_reachable {
  277. cfg.add(vartab, Instr::Branch { block: cond });
  278. }
  279. cfg.set_basic_block(cond);
  280. let cond_expr = expression(cond_expr, cfg, contract_no, Some(func), ns, vartab, opt);
  281. cfg.add(
  282. vartab,
  283. Instr::BranchCond {
  284. cond: cond_expr,
  285. true_block: body,
  286. false_block: end,
  287. },
  288. );
  289. let set = vartab.pop_dirty_tracker();
  290. cfg.set_phis(end, set.clone());
  291. cfg.set_phis(body, set.clone());
  292. cfg.set_phis(cond, set);
  293. cfg.set_basic_block(end);
  294. }
  295. Statement::While(_, _, cond_expr, body_stmt) => {
  296. let cond = cfg.new_basic_block("cond".to_string());
  297. let body = cfg.new_basic_block("body".to_string());
  298. let end = cfg.new_basic_block("endwhile".to_string());
  299. cfg.add(vartab, Instr::Branch { block: cond });
  300. cfg.set_basic_block(cond);
  301. let cond_expr = expression(cond_expr, cfg, contract_no, Some(func), ns, vartab, opt);
  302. cfg.add(
  303. vartab,
  304. Instr::BranchCond {
  305. cond: cond_expr,
  306. true_block: body,
  307. false_block: end,
  308. },
  309. );
  310. cfg.set_basic_block(body);
  311. vartab.new_dirty_tracker();
  312. loops.new_scope(end, cond);
  313. let mut body_reachable = true;
  314. for stmt in body_stmt {
  315. statement(
  316. stmt,
  317. func,
  318. cfg,
  319. contract_no,
  320. ns,
  321. vartab,
  322. loops,
  323. placeholder,
  324. return_override,
  325. opt,
  326. );
  327. body_reachable = stmt.reachable();
  328. }
  329. if body_reachable {
  330. cfg.add(vartab, Instr::Branch { block: cond });
  331. }
  332. loops.leave_scope();
  333. let set = vartab.pop_dirty_tracker();
  334. cfg.set_phis(end, set.clone());
  335. cfg.set_phis(cond, set);
  336. cfg.set_basic_block(end);
  337. }
  338. Statement::For {
  339. init,
  340. cond: None,
  341. next,
  342. body,
  343. ..
  344. } => {
  345. let body_block = cfg.new_basic_block("body".to_string());
  346. let next_block = cfg.new_basic_block("next".to_string());
  347. let end_block = cfg.new_basic_block("endfor".to_string());
  348. for stmt in init {
  349. statement(
  350. stmt,
  351. func,
  352. cfg,
  353. contract_no,
  354. ns,
  355. vartab,
  356. loops,
  357. placeholder,
  358. return_override,
  359. opt,
  360. );
  361. }
  362. cfg.add(vartab, Instr::Branch { block: body_block });
  363. cfg.set_basic_block(body_block);
  364. loops.new_scope(
  365. end_block,
  366. if next.is_none() {
  367. body_block
  368. } else {
  369. next_block
  370. },
  371. );
  372. vartab.new_dirty_tracker();
  373. let mut body_reachable = true;
  374. for stmt in body {
  375. statement(
  376. stmt,
  377. func,
  378. cfg,
  379. contract_no,
  380. ns,
  381. vartab,
  382. loops,
  383. placeholder,
  384. return_override,
  385. opt,
  386. );
  387. body_reachable = stmt.reachable();
  388. }
  389. if body_reachable {
  390. cfg.add(vartab, Instr::Branch { block: next_block });
  391. }
  392. loops.leave_scope();
  393. if body_reachable {
  394. cfg.set_basic_block(next_block);
  395. if let Some(next) = next {
  396. expression(next, cfg, contract_no, Some(func), ns, vartab, opt);
  397. body_reachable = next.ty() != Type::Unreachable;
  398. }
  399. if body_reachable {
  400. cfg.add(vartab, Instr::Branch { block: body_block });
  401. }
  402. }
  403. let set = vartab.pop_dirty_tracker();
  404. cfg.set_phis(next_block, set.clone());
  405. cfg.set_phis(body_block, set.clone());
  406. cfg.set_phis(end_block, set);
  407. cfg.set_basic_block(end_block);
  408. }
  409. Statement::For {
  410. init,
  411. cond: Some(cond_expr),
  412. next,
  413. body,
  414. ..
  415. } => {
  416. let body_block = cfg.new_basic_block("body".to_string());
  417. let cond_block = cfg.new_basic_block("cond".to_string());
  418. let next_block = cfg.new_basic_block("next".to_string());
  419. let end_block = cfg.new_basic_block("endfor".to_string());
  420. for stmt in init {
  421. statement(
  422. stmt,
  423. func,
  424. cfg,
  425. contract_no,
  426. ns,
  427. vartab,
  428. loops,
  429. placeholder,
  430. return_override,
  431. opt,
  432. );
  433. }
  434. cfg.add(vartab, Instr::Branch { block: cond_block });
  435. cfg.set_basic_block(cond_block);
  436. let cond_expr = expression(cond_expr, cfg, contract_no, Some(func), ns, vartab, opt);
  437. cfg.add(
  438. vartab,
  439. Instr::BranchCond {
  440. cond: cond_expr,
  441. true_block: body_block,
  442. false_block: end_block,
  443. },
  444. );
  445. cfg.set_basic_block(body_block);
  446. // continue goes to next
  447. loops.new_scope(end_block, next_block);
  448. vartab.new_dirty_tracker();
  449. let mut body_reachable = true;
  450. for stmt in body {
  451. statement(
  452. stmt,
  453. func,
  454. cfg,
  455. contract_no,
  456. ns,
  457. vartab,
  458. loops,
  459. placeholder,
  460. return_override,
  461. opt,
  462. );
  463. body_reachable = stmt.reachable();
  464. }
  465. if body_reachable {
  466. cfg.add(vartab, Instr::Branch { block: next_block });
  467. }
  468. loops.leave_scope();
  469. cfg.set_basic_block(next_block);
  470. let mut next_reachable = true;
  471. if let Some(next) = next {
  472. expression(next, cfg, contract_no, Some(func), ns, vartab, opt);
  473. next_reachable = next.ty() != Type::Unreachable;
  474. }
  475. if next_reachable {
  476. cfg.add(vartab, Instr::Branch { block: cond_block });
  477. }
  478. cfg.set_basic_block(end_block);
  479. let set = vartab.pop_dirty_tracker();
  480. cfg.set_phis(next_block, set.clone());
  481. cfg.set_phis(end_block, set.clone());
  482. cfg.set_phis(cond_block, set);
  483. }
  484. Statement::Destructure(_, fields, expr) => {
  485. destructure(fields, expr, cfg, contract_no, func, ns, vartab, opt)
  486. }
  487. Statement::TryCatch(_, _, try_stmt) => try_catch(
  488. try_stmt,
  489. func,
  490. cfg,
  491. contract_no,
  492. ns,
  493. vartab,
  494. loops,
  495. placeholder,
  496. return_override,
  497. opt,
  498. ),
  499. Statement::Emit {
  500. loc,
  501. event_no,
  502. args,
  503. ..
  504. } => {
  505. let emitter = new_event_emitter(loc, *event_no, args, ns);
  506. emitter.emit(contract_no, func, cfg, vartab, opt);
  507. }
  508. Statement::Revert {
  509. loc,
  510. error_no,
  511. args,
  512. } => {
  513. assert!(error_no.is_none());
  514. revert(args, cfg, contract_no, Some(func), ns, vartab, opt, loc);
  515. }
  516. Statement::Underscore(_) => {
  517. // ensure we get phi nodes for the return values
  518. if let Some(instr @ Instr::Call { res, .. }) = placeholder {
  519. for var_no in res {
  520. vartab.set_dirty(*var_no);
  521. }
  522. cfg.add(vartab, instr.clone());
  523. } else {
  524. panic!("placeholder should be provided for modifiers");
  525. }
  526. }
  527. Statement::Assembly(inline_assembly, ..) => {
  528. inline_assembly_cfg(inline_assembly, contract_no, ns, cfg, vartab, opt);
  529. }
  530. }
  531. }
  532. fn revert(
  533. args: &[ast::Expression],
  534. cfg: &mut ControlFlowGraph,
  535. contract_no: usize,
  536. func: Option<&Function>,
  537. ns: &Namespace,
  538. vartab: &mut Vartable,
  539. opt: &Options,
  540. loc: &pt::Loc,
  541. ) {
  542. let expr = args
  543. .get(0)
  544. .map(|s| expression(s, cfg, contract_no, func, ns, vartab, opt));
  545. if opt.log_runtime_errors {
  546. if expr.is_some() {
  547. let prefix = b"runtime_error: ";
  548. let error_string = format!(
  549. " revert encountered in {},\n",
  550. ns.loc_to_string(PathDisplay::Filename, loc)
  551. );
  552. let print_expr = Expression::FormatString {
  553. loc: Codegen,
  554. args: vec![
  555. (
  556. FormatArg::StringLiteral,
  557. Expression::BytesLiteral {
  558. loc: Codegen,
  559. ty: Type::Bytes(prefix.len() as u8),
  560. value: prefix.to_vec(),
  561. },
  562. ),
  563. (FormatArg::Default, expr.clone().unwrap()),
  564. (
  565. FormatArg::StringLiteral,
  566. Expression::BytesLiteral {
  567. loc: Codegen,
  568. ty: Type::Bytes(error_string.as_bytes().len() as u8),
  569. value: error_string.as_bytes().to_vec(),
  570. },
  571. ),
  572. ],
  573. };
  574. cfg.add(vartab, Instr::Print { expr: print_expr });
  575. } else {
  576. log_runtime_error(
  577. opt.log_runtime_errors,
  578. "revert encountered",
  579. *loc,
  580. cfg,
  581. vartab,
  582. ns,
  583. )
  584. }
  585. }
  586. assert_failure(&Codegen, expr, ns, cfg, vartab);
  587. }
  588. /// Generate if-then-no-else
  589. fn if_then(
  590. cond: &ast::Expression,
  591. then_stmt: &[Statement],
  592. func: &Function,
  593. cfg: &mut ControlFlowGraph,
  594. contract_no: usize,
  595. ns: &Namespace,
  596. vartab: &mut Vartable,
  597. loops: &mut LoopScopes,
  598. placeholder: Option<&Instr>,
  599. return_override: Option<&Instr>,
  600. opt: &Options,
  601. ) {
  602. let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
  603. let then = cfg.new_basic_block("then".to_string());
  604. let endif = cfg.new_basic_block("endif".to_string());
  605. cfg.add(
  606. vartab,
  607. Instr::BranchCond {
  608. cond,
  609. true_block: then,
  610. false_block: endif,
  611. },
  612. );
  613. cfg.set_basic_block(then);
  614. vartab.new_dirty_tracker();
  615. let mut reachable = true;
  616. for stmt in then_stmt {
  617. statement(
  618. stmt,
  619. func,
  620. cfg,
  621. contract_no,
  622. ns,
  623. vartab,
  624. loops,
  625. placeholder,
  626. return_override,
  627. opt,
  628. );
  629. reachable = stmt.reachable();
  630. }
  631. if reachable {
  632. cfg.add(vartab, Instr::Branch { block: endif });
  633. }
  634. cfg.set_phis(endif, vartab.pop_dirty_tracker());
  635. cfg.set_basic_block(endif);
  636. }
  637. /// Generate if-then-else
  638. fn if_then_else(
  639. cond: &ast::Expression,
  640. then_stmt: &[Statement],
  641. else_stmt: &[Statement],
  642. func: &Function,
  643. cfg: &mut ControlFlowGraph,
  644. contract_no: usize,
  645. ns: &Namespace,
  646. vartab: &mut Vartable,
  647. loops: &mut LoopScopes,
  648. placeholder: Option<&Instr>,
  649. return_override: Option<&Instr>,
  650. opt: &Options,
  651. ) {
  652. let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
  653. let then = cfg.new_basic_block("then".to_string());
  654. let else_ = cfg.new_basic_block("else".to_string());
  655. let endif = cfg.new_basic_block("endif".to_string());
  656. cfg.add(
  657. vartab,
  658. Instr::BranchCond {
  659. cond,
  660. true_block: then,
  661. false_block: else_,
  662. },
  663. );
  664. // then
  665. cfg.set_basic_block(then);
  666. vartab.new_dirty_tracker();
  667. let mut then_reachable = true;
  668. for stmt in then_stmt {
  669. statement(
  670. stmt,
  671. func,
  672. cfg,
  673. contract_no,
  674. ns,
  675. vartab,
  676. loops,
  677. placeholder,
  678. return_override,
  679. opt,
  680. );
  681. then_reachable = stmt.reachable();
  682. }
  683. if then_reachable {
  684. cfg.add(vartab, Instr::Branch { block: endif });
  685. }
  686. // else
  687. cfg.set_basic_block(else_);
  688. let mut else_reachable = true;
  689. for stmt in else_stmt {
  690. statement(
  691. stmt,
  692. func,
  693. cfg,
  694. contract_no,
  695. ns,
  696. vartab,
  697. loops,
  698. placeholder,
  699. return_override,
  700. opt,
  701. );
  702. else_reachable = stmt.reachable();
  703. }
  704. if else_reachable {
  705. cfg.add(vartab, Instr::Branch { block: endif });
  706. }
  707. cfg.set_phis(endif, vartab.pop_dirty_tracker());
  708. cfg.set_basic_block(endif);
  709. }
  710. fn returns(
  711. expr: &ast::Expression,
  712. cfg: &mut ControlFlowGraph,
  713. contract_no: usize,
  714. func: &Function,
  715. ns: &Namespace,
  716. vartab: &mut Vartable,
  717. opt: &Options,
  718. ) {
  719. // Can only be another function call without returns
  720. let uncast_values = match expr {
  721. // Explicitly recurse for conditinal operator expressions.
  722. // `return a ? b : c` is transformed into pseudo code `a ? return b : return c`
  723. ast::Expression::ConditionalOperator {
  724. cond,
  725. true_option: left,
  726. false_option: right,
  727. ..
  728. } => {
  729. let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
  730. let left_block = cfg.new_basic_block("left".to_string());
  731. let right_block = cfg.new_basic_block("right".to_string());
  732. cfg.add(
  733. vartab,
  734. Instr::BranchCond {
  735. cond,
  736. true_block: left_block,
  737. false_block: right_block,
  738. },
  739. );
  740. vartab.new_dirty_tracker();
  741. cfg.set_basic_block(left_block);
  742. returns(left, cfg, contract_no, func, ns, vartab, opt);
  743. cfg.set_basic_block(right_block);
  744. returns(right, cfg, contract_no, func, ns, vartab, opt);
  745. return;
  746. }
  747. ast::Expression::Builtin {
  748. kind: ast::Builtin::AbiDecode,
  749. ..
  750. }
  751. | ast::Expression::InternalFunctionCall { .. }
  752. | ast::Expression::ExternalFunctionCall { .. }
  753. | ast::Expression::ExternalFunctionCallRaw { .. } => {
  754. emit_function_call(expr, contract_no, cfg, Some(func), ns, vartab, opt)
  755. }
  756. ast::Expression::List { list, .. } => list
  757. .iter()
  758. .map(|e| expression(e, cfg, contract_no, Some(func), ns, vartab, opt))
  759. .collect::<Vec<Expression>>(),
  760. // Can be any other expression
  761. _ => {
  762. vec![expression(
  763. expr,
  764. cfg,
  765. contract_no,
  766. Some(func),
  767. ns,
  768. vartab,
  769. opt,
  770. )]
  771. }
  772. };
  773. let cast_values = func
  774. .returns
  775. .iter()
  776. .zip(uncast_values)
  777. .map(|(left, right)| try_load_and_cast(&right.loc(), &right, &left.ty, ns, cfg, vartab))
  778. .collect();
  779. cfg.add(vartab, Instr::Return { value: cast_values });
  780. }
  781. fn destructure(
  782. fields: &[DestructureField],
  783. expr: &ast::Expression,
  784. cfg: &mut ControlFlowGraph,
  785. contract_no: usize,
  786. func: &Function,
  787. ns: &Namespace,
  788. vartab: &mut Vartable,
  789. opt: &Options,
  790. ) {
  791. if let ast::Expression::ConditionalOperator {
  792. cond,
  793. true_option: left,
  794. false_option: right,
  795. ..
  796. } = expr
  797. {
  798. let cond = expression(cond, cfg, contract_no, Some(func), ns, vartab, opt);
  799. let left_block = cfg.new_basic_block("left".to_string());
  800. let right_block = cfg.new_basic_block("right".to_string());
  801. let done_block = cfg.new_basic_block("done".to_string());
  802. cfg.add(
  803. vartab,
  804. Instr::BranchCond {
  805. cond,
  806. true_block: left_block,
  807. false_block: right_block,
  808. },
  809. );
  810. vartab.new_dirty_tracker();
  811. cfg.set_basic_block(left_block);
  812. destructure(fields, left, cfg, contract_no, func, ns, vartab, opt);
  813. cfg.add(vartab, Instr::Branch { block: done_block });
  814. cfg.set_basic_block(right_block);
  815. destructure(fields, right, cfg, contract_no, func, ns, vartab, opt);
  816. cfg.add(vartab, Instr::Branch { block: done_block });
  817. cfg.set_phis(done_block, vartab.pop_dirty_tracker());
  818. cfg.set_basic_block(done_block);
  819. return;
  820. }
  821. let mut values = match expr {
  822. ast::Expression::List { list, .. } => {
  823. let mut values = Vec::new();
  824. for expr in list {
  825. let loc = expr.loc();
  826. let expr = expression(expr, cfg, contract_no, Some(func), ns, vartab, opt);
  827. let ty = expr.ty();
  828. let res = vartab.temp_anonymous(&ty);
  829. cfg.add(vartab, Instr::Set { loc, res, expr });
  830. values.push(Expression::Variable {
  831. loc,
  832. ty,
  833. var_no: res,
  834. });
  835. }
  836. values
  837. }
  838. _ => {
  839. // must be function call, either internal or external
  840. emit_function_call(expr, contract_no, cfg, Some(func), ns, vartab, opt)
  841. }
  842. };
  843. for field in fields.iter() {
  844. let right = values.remove(0);
  845. match field {
  846. DestructureField::None => {
  847. // nothing to do
  848. }
  849. DestructureField::VariableDecl(res, param) => {
  850. let expr = try_load_and_cast(&param.loc, &right, &param.ty, ns, cfg, vartab);
  851. if should_remove_variable(*res, func, opt) {
  852. continue;
  853. }
  854. cfg.add(
  855. vartab,
  856. Instr::Set {
  857. loc: param.loc,
  858. res: *res,
  859. expr,
  860. },
  861. );
  862. }
  863. DestructureField::Expression(left) => {
  864. let expr = try_load_and_cast(&left.loc(), &right, &left.ty(), ns, cfg, vartab);
  865. if should_remove_assignment(ns, left, func, opt) {
  866. continue;
  867. }
  868. assign_single(left, expr, cfg, contract_no, Some(func), ns, vartab, opt);
  869. }
  870. }
  871. }
  872. }
  873. /// During a destructure statement, sema only checks if the cast is possible. During codegen, we
  874. /// perform the real cast and add an instruction to the CFG to load a value from the storage if want it.
  875. /// The existing codegen cast function does not manage the CFG, so the loads must be done here.
  876. fn try_load_and_cast(
  877. loc: &pt::Loc,
  878. expr: &Expression,
  879. to_ty: &Type,
  880. ns: &Namespace,
  881. cfg: &mut ControlFlowGraph,
  882. vartab: &mut Vartable,
  883. ) -> Expression {
  884. match expr.ty() {
  885. Type::StorageRef(_, ty) => {
  886. if let Expression::Subscript { array_ty, .. } = &expr {
  887. if array_ty.is_storage_bytes() {
  888. return expr.cast(to_ty, ns);
  889. }
  890. }
  891. if matches!(to_ty, Type::StorageRef(..)) {
  892. // If we want a storage reference, there is no need to load from storage
  893. return expr.cast(to_ty, ns);
  894. }
  895. let anonymous_no = vartab.temp_anonymous(&ty);
  896. cfg.add(
  897. vartab,
  898. Instr::LoadStorage {
  899. res: anonymous_no,
  900. ty: (*ty).clone(),
  901. storage: expr.cast(to_ty, ns),
  902. },
  903. );
  904. Expression::Variable {
  905. loc: *loc,
  906. ty: (*ty).clone(),
  907. var_no: anonymous_no,
  908. }
  909. }
  910. Type::Ref(ty) => match *ty {
  911. Type::Array(_, _) => expr.cast(to_ty, ns),
  912. _ => Expression::Load {
  913. loc: pt::Loc::Builtin,
  914. ty: *ty,
  915. expr: expr.clone().into(),
  916. }
  917. .cast(to_ty, ns),
  918. },
  919. _ => expr.cast(to_ty, ns),
  920. }
  921. }
  922. /// Resolve try catch statement
  923. fn try_catch(
  924. try_stmt: &TryCatch,
  925. func: &Function,
  926. cfg: &mut ControlFlowGraph,
  927. callee_contract_no: usize,
  928. ns: &Namespace,
  929. vartab: &mut Vartable,
  930. loops: &mut LoopScopes,
  931. placeholder: Option<&Instr>,
  932. return_override: Option<&Instr>,
  933. opt: &Options,
  934. ) {
  935. let success = vartab.temp(
  936. &pt::Identifier {
  937. loc: try_stmt.expr.loc(),
  938. name: "success".to_owned(),
  939. },
  940. &Type::Bool,
  941. );
  942. let success_block = cfg.new_basic_block("success".to_string());
  943. let catch_block = cfg.new_basic_block("catch".to_string());
  944. let finally_block = cfg.new_basic_block("finally".to_string());
  945. match &try_stmt.expr {
  946. ast::Expression::ExternalFunctionCall {
  947. loc,
  948. function,
  949. args,
  950. call_args,
  951. ..
  952. } => {
  953. if let Type::ExternalFunction {
  954. returns: func_returns,
  955. ..
  956. } = function.ty()
  957. {
  958. let value = if let Some(value) = &call_args.value {
  959. expression(value, cfg, callee_contract_no, Some(func), ns, vartab, opt)
  960. } else {
  961. Expression::NumberLiteral {
  962. loc: Codegen,
  963. ty: Type::Value,
  964. value: BigInt::zero(),
  965. }
  966. };
  967. let gas = if let Some(gas) = &call_args.gas {
  968. expression(gas, cfg, callee_contract_no, Some(func), ns, vartab, opt)
  969. } else {
  970. default_gas(ns)
  971. };
  972. let function = expression(
  973. function,
  974. cfg,
  975. callee_contract_no,
  976. Some(func),
  977. ns,
  978. vartab,
  979. opt,
  980. );
  981. let mut args = args
  982. .iter()
  983. .map(|a| expression(a, cfg, callee_contract_no, Some(func), ns, vartab, opt))
  984. .collect::<Vec<Expression>>();
  985. let selector = function.external_function_selector();
  986. let address = function.external_function_address();
  987. args.insert(0, selector);
  988. let (payload, _) = abi_encode(loc, args, ns, vartab, cfg, false);
  989. let flags = call_args.flags.as_ref().map(|expr| {
  990. expression(expr, cfg, callee_contract_no, Some(func), ns, vartab, opt)
  991. });
  992. cfg.add(
  993. vartab,
  994. Instr::ExternalCall {
  995. success: Some(success),
  996. address: Some(address),
  997. accounts: None,
  998. seeds: None,
  999. payload,
  1000. value,
  1001. gas,
  1002. callty: CallTy::Regular,
  1003. contract_function_no: None,
  1004. flags,
  1005. },
  1006. );
  1007. cfg.add(
  1008. vartab,
  1009. Instr::BranchCond {
  1010. cond: Expression::Variable {
  1011. loc: try_stmt.expr.loc(),
  1012. ty: Type::Bool,
  1013. var_no: success,
  1014. },
  1015. true_block: success_block,
  1016. false_block: catch_block,
  1017. },
  1018. );
  1019. cfg.set_basic_block(success_block);
  1020. if !try_stmt.returns.is_empty() {
  1021. let mut res = Vec::new();
  1022. for ret in &try_stmt.returns {
  1023. res.push(match ret {
  1024. (Some(pos), _) => *pos,
  1025. (None, param) => vartab.temp_anonymous(&param.ty),
  1026. });
  1027. }
  1028. let buf = &Expression::ReturnData { loc: Codegen };
  1029. let decoded = abi_decode(&Codegen, buf, &func_returns, ns, vartab, cfg, None);
  1030. for instruction in res.iter().zip(decoded).map(|(var, expr)| Instr::Set {
  1031. loc: Codegen,
  1032. res: *var,
  1033. expr,
  1034. }) {
  1035. cfg.add(vartab, instruction)
  1036. }
  1037. }
  1038. } else {
  1039. // dynamic dispatch
  1040. unimplemented!();
  1041. }
  1042. }
  1043. ast::Expression::Constructor {
  1044. loc,
  1045. contract_no,
  1046. constructor_no,
  1047. args,
  1048. call_args,
  1049. ..
  1050. } => {
  1051. let address_res = match try_stmt.returns.get(0) {
  1052. Some((Some(pos), _)) => *pos,
  1053. _ => vartab.temp_anonymous(&Type::Contract(*contract_no)),
  1054. };
  1055. call_constructor(
  1056. loc,
  1057. *contract_no,
  1058. callee_contract_no,
  1059. constructor_no,
  1060. args,
  1061. call_args,
  1062. address_res,
  1063. Some(success),
  1064. Some(func),
  1065. ns,
  1066. vartab,
  1067. cfg,
  1068. opt,
  1069. );
  1070. cfg.add(
  1071. vartab,
  1072. Instr::BranchCond {
  1073. cond: Expression::Variable {
  1074. loc: try_stmt.expr.loc(),
  1075. ty: Type::Bool,
  1076. var_no: success,
  1077. },
  1078. true_block: success_block,
  1079. false_block: catch_block,
  1080. },
  1081. );
  1082. cfg.set_basic_block(success_block);
  1083. }
  1084. _ => unreachable!(),
  1085. }
  1086. vartab.new_dirty_tracker();
  1087. let mut finally_reachable = true;
  1088. for stmt in &try_stmt.ok_stmt {
  1089. statement(
  1090. stmt,
  1091. func,
  1092. cfg,
  1093. callee_contract_no,
  1094. ns,
  1095. vartab,
  1096. loops,
  1097. placeholder,
  1098. return_override,
  1099. opt,
  1100. );
  1101. finally_reachable = stmt.reachable();
  1102. }
  1103. if finally_reachable {
  1104. cfg.add(
  1105. vartab,
  1106. Instr::Branch {
  1107. block: finally_block,
  1108. },
  1109. );
  1110. }
  1111. cfg.set_basic_block(catch_block);
  1112. for (error_param_pos, error_param, error_stmt) in &try_stmt.errors {
  1113. let no_reason_block = cfg.new_basic_block("no_reason".to_string());
  1114. let error_var = match error_param_pos {
  1115. Some(pos) => *pos,
  1116. _ => vartab.temp_anonymous(&Type::String),
  1117. };
  1118. // Expect the returned data to match the 4 bytes function selector for "Error(string)"
  1119. let buf = &Expression::ReturnData { loc: Codegen };
  1120. let tys = &[Type::Bytes(4), error_param.ty.clone()];
  1121. let decoded = abi_decode(&Codegen, buf, tys, ns, vartab, cfg, None);
  1122. let err_id = Expression::NumberLiteral {
  1123. loc: Codegen,
  1124. ty: Type::Bytes(4),
  1125. value: 0x08c3_79a0.into(),
  1126. }
  1127. .into();
  1128. let cond = Expression::Equal {
  1129. loc: Codegen,
  1130. left: decoded[0].clone().into(),
  1131. right: err_id,
  1132. };
  1133. let match_err_id = cfg.new_basic_block("match_err_id".into());
  1134. let no_match_err_id = cfg.new_basic_block("no_match_err_id".into());
  1135. let instruction = Instr::BranchCond {
  1136. cond,
  1137. true_block: match_err_id,
  1138. false_block: no_match_err_id,
  1139. };
  1140. cfg.add(vartab, instruction);
  1141. cfg.set_basic_block(no_match_err_id);
  1142. cfg.add(vartab, Instr::AssertFailure { encoded_args: None });
  1143. cfg.set_basic_block(match_err_id);
  1144. let instruction = Instr::Set {
  1145. loc: Codegen,
  1146. res: error_var,
  1147. expr: decoded[1].clone(),
  1148. };
  1149. cfg.add(vartab, instruction);
  1150. let mut reachable = true;
  1151. for stmt in error_stmt {
  1152. statement(
  1153. stmt,
  1154. func,
  1155. cfg,
  1156. callee_contract_no,
  1157. ns,
  1158. vartab,
  1159. loops,
  1160. placeholder,
  1161. return_override,
  1162. opt,
  1163. );
  1164. reachable = stmt.reachable();
  1165. }
  1166. if reachable {
  1167. cfg.add(
  1168. vartab,
  1169. Instr::Branch {
  1170. block: finally_block,
  1171. },
  1172. );
  1173. }
  1174. cfg.set_basic_block(no_reason_block);
  1175. }
  1176. if let Some(res) = try_stmt.catch_param_pos {
  1177. let instruction = Instr::Set {
  1178. loc: Codegen,
  1179. res,
  1180. expr: Expression::ReturnData { loc: Codegen },
  1181. };
  1182. cfg.add(vartab, instruction);
  1183. }
  1184. let mut reachable = true;
  1185. for stmt in &try_stmt.catch_stmt {
  1186. statement(
  1187. stmt,
  1188. func,
  1189. cfg,
  1190. callee_contract_no,
  1191. ns,
  1192. vartab,
  1193. loops,
  1194. placeholder,
  1195. return_override,
  1196. opt,
  1197. );
  1198. reachable = stmt.reachable();
  1199. }
  1200. if reachable {
  1201. cfg.add(
  1202. vartab,
  1203. Instr::Branch {
  1204. block: finally_block,
  1205. },
  1206. );
  1207. }
  1208. let mut set = vartab.pop_dirty_tracker();
  1209. if let Some(pos) = &try_stmt.catch_param_pos {
  1210. set.remove(pos);
  1211. }
  1212. for (pos, _, _) in &try_stmt.errors {
  1213. if let Some(pos) = pos {
  1214. set.remove(pos);
  1215. }
  1216. }
  1217. cfg.set_phis(finally_block, set);
  1218. cfg.set_basic_block(finally_block);
  1219. }
  1220. pub struct LoopScope {
  1221. break_bb: usize,
  1222. continue_bb: usize,
  1223. }
  1224. pub struct LoopScopes(Vec<LoopScope>);
  1225. impl LoopScopes {
  1226. pub fn new() -> Self {
  1227. LoopScopes(Vec::new())
  1228. }
  1229. pub(crate) fn new_scope(&mut self, break_bb: usize, continue_bb: usize) {
  1230. self.0.push(LoopScope {
  1231. break_bb,
  1232. continue_bb,
  1233. })
  1234. }
  1235. pub(crate) fn leave_scope(&mut self) -> LoopScope {
  1236. self.0.pop().expect("should be in loop scope")
  1237. }
  1238. pub(crate) fn do_break(&mut self) -> usize {
  1239. self.0.last().unwrap().break_bb
  1240. }
  1241. pub(crate) fn do_continue(&mut self) -> usize {
  1242. self.0.last().unwrap().continue_bb
  1243. }
  1244. }
  1245. impl Type {
  1246. /// Default value for a type, e.g. an empty string. Some types cannot have a default value,
  1247. /// for example a reference to a variable in storage.
  1248. pub fn default(&self, ns: &Namespace) -> Option<Expression> {
  1249. match self {
  1250. Type::Address(_) | Uint(_) | Type::Int(_) => Some(Expression::NumberLiteral {
  1251. loc: Codegen,
  1252. ty: self.clone(),
  1253. value: BigInt::from(0),
  1254. }),
  1255. Type::Bool => Some(Expression::BoolLiteral {
  1256. loc: Codegen,
  1257. value: false,
  1258. }),
  1259. Type::Bytes(n) => {
  1260. let mut l = Vec::new();
  1261. l.resize(*n as usize, 0);
  1262. Some(Expression::BytesLiteral {
  1263. loc: Codegen,
  1264. ty: self.clone(),
  1265. value: l,
  1266. })
  1267. }
  1268. Type::Enum(e) => ns.enums[*e].ty.default(ns),
  1269. Type::Struct(struct_ty) => {
  1270. // make sure all our fields have default values
  1271. for field in &struct_ty.definition(ns).fields {
  1272. field.ty.default(ns)?;
  1273. }
  1274. Some(Expression::StructLiteral {
  1275. loc: Codegen,
  1276. ty: self.clone(),
  1277. values: Vec::new(),
  1278. })
  1279. }
  1280. Type::Ref(ty) => {
  1281. assert!(matches!(ty.as_ref(), Type::Address(_)));
  1282. Some(Expression::GetRef {
  1283. loc: Codegen,
  1284. ty: Type::Ref(Box::new(ty.as_ref().clone())),
  1285. expr: Box::new(Expression::NumberLiteral {
  1286. loc: Codegen,
  1287. ty: ty.as_ref().clone(),
  1288. value: BigInt::from(0),
  1289. }),
  1290. })
  1291. }
  1292. Type::StorageRef(..) => None,
  1293. Type::String | Type::DynamicBytes => Some(Expression::AllocDynamicBytes {
  1294. loc: Codegen,
  1295. ty: self.clone(),
  1296. size: Box::new(Expression::NumberLiteral {
  1297. loc: Codegen,
  1298. ty: Uint(32),
  1299. value: BigInt::zero(),
  1300. }),
  1301. initializer: None,
  1302. }),
  1303. Type::InternalFunction { .. } | Type::Contract(_) | Type::ExternalFunction { .. } => {
  1304. None
  1305. }
  1306. Type::Array(ty, dims) => {
  1307. ty.default(ns)?;
  1308. if dims.last() == Some(&ArrayLength::Dynamic) {
  1309. Some(Expression::AllocDynamicBytes {
  1310. loc: Codegen,
  1311. ty: self.clone(),
  1312. size: Box::new(Expression::NumberLiteral {
  1313. loc: Codegen,
  1314. ty: Uint(32),
  1315. value: BigInt::zero(),
  1316. }),
  1317. initializer: None,
  1318. })
  1319. } else {
  1320. Some(Expression::ArrayLiteral {
  1321. loc: Codegen,
  1322. ty: self.clone(),
  1323. dimensions: Vec::new(),
  1324. values: Vec::new(),
  1325. })
  1326. }
  1327. }
  1328. _ => None,
  1329. }
  1330. }
  1331. }
  1332. impl Namespace {
  1333. /// Phoney default constructor
  1334. pub fn default_constructor(&self, contract_no: usize) -> Function {
  1335. let mut func = Function::new(
  1336. Codegen,
  1337. "".to_owned(),
  1338. Some(contract_no),
  1339. vec![],
  1340. pt::FunctionTy::Constructor,
  1341. None,
  1342. pt::Visibility::Public(None),
  1343. Vec::new(),
  1344. Vec::new(),
  1345. self,
  1346. );
  1347. func.body = vec![Statement::Return(Codegen, None)];
  1348. func.has_body = true;
  1349. func
  1350. }
  1351. }
  1352. /// This function looks for expressions that have side effects during code execution and
  1353. /// processes them.
  1354. /// They must be added to the cfg event if we remove the assignment
  1355. pub fn process_side_effects_expressions(
  1356. exp: &ast::Expression,
  1357. ctx: &mut SideEffectsCheckParameters,
  1358. ) -> bool {
  1359. match &exp {
  1360. ast::Expression::InternalFunctionCall { .. }
  1361. | ast::Expression::ExternalFunctionCall { .. }
  1362. | ast::Expression::ExternalFunctionCallRaw { .. }
  1363. | ast::Expression::Constructor { .. }
  1364. | ast::Expression::Assign { .. } => {
  1365. let _ = expression(
  1366. exp,
  1367. ctx.cfg,
  1368. ctx.contract_no,
  1369. ctx.func,
  1370. ctx.ns,
  1371. ctx.vartab,
  1372. ctx.opt,
  1373. );
  1374. false
  1375. }
  1376. ast::Expression::Builtin {
  1377. kind: builtin_type, ..
  1378. } => match &builtin_type {
  1379. ast::Builtin::PayableSend
  1380. | ast::Builtin::ArrayPush
  1381. | ast::Builtin::ArrayPop
  1382. // PayableTransfer, Revert, Require and SelfDestruct do not occur inside an expression
  1383. // for they return no value. They should not bother the unused variable elimination.
  1384. | ast::Builtin::PayableTransfer
  1385. | ast::Builtin::Require
  1386. | ast::Builtin::SelfDestruct
  1387. | ast::Builtin::WriteInt8
  1388. | ast::Builtin::WriteInt16LE
  1389. | ast::Builtin::WriteInt32LE
  1390. | ast::Builtin::WriteInt64LE
  1391. | ast::Builtin::WriteInt128LE
  1392. | ast::Builtin::WriteInt256LE
  1393. | ast::Builtin::WriteUint16LE
  1394. | ast::Builtin::WriteUint32LE
  1395. | ast::Builtin::WriteUint64LE
  1396. | ast::Builtin::WriteUint128LE
  1397. | ast::Builtin::WriteUint256LE
  1398. | ast::Builtin::WriteAddress => {
  1399. let _ = expression(exp, ctx.cfg, ctx.contract_no, ctx.func, ctx.ns, ctx.vartab, ctx.opt);
  1400. false
  1401. }
  1402. _ => true,
  1403. },
  1404. _ => true,
  1405. }
  1406. }