statements.rs 43 KB

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