@@ -5,7 +5,7 @@ use crate::builtins::{
55use crate :: context:: { AnalyzerContext , CallType , ExpressionAttributes , Location , NamedThing } ;
66use crate :: errors:: { FatalError , IndexingError , NotFixedSize } ;
77use crate :: namespace:: items:: { ContractId , FunctionId , Item } ;
8- use crate :: namespace:: scopes:: BlockScope ;
8+ use crate :: namespace:: scopes:: { BlockScope , BlockScopeType } ;
99use crate :: namespace:: types:: {
1010 Array , Base , Contract , FeString , Integer , SelfDecl , Struct , Tuple , Type , TypeDowncast , U256 ,
1111} ;
@@ -19,6 +19,7 @@ use fe_common::Span;
1919use fe_parser:: ast as fe;
2020use fe_parser:: ast:: UnaryOperator ;
2121use fe_parser:: node:: Node ;
22+ use if_chain:: if_chain;
2223use num_bigint:: BigInt ;
2324use std:: convert:: TryInto ;
2425use std:: ops:: RangeInclusive ;
@@ -732,7 +733,7 @@ fn expr_call(
732733 func_name,
733734 self_span,
734735 } => expr_call_self_attribute ( scope, & func_name, func. span , self_span, args) ,
735- CallType :: Pure ( func_id) => expr_call_pure ( scope, func_id, args) ,
736+ CallType :: Pure ( func_id) => expr_call_pure ( scope, func . span , func_id, args) ,
736737 CallType :: ValueAttribute => expr_call_value_attribute ( scope, func, args) ,
737738 CallType :: TypeAttribute { typ, func_name } => {
738739 expr_call_type_attribute ( scope, typ, & func_name, func. span , args)
@@ -963,6 +964,27 @@ fn resolve_self(scope: &mut BlockScope, use_span: Span) -> Result<ContractId, Fa
963964 Ok ( contract)
964965}
965966
967+ fn check_for_unsafe_call_outside_unsafe (
968+ scope : & mut BlockScope ,
969+ fn_name : & str ,
970+ call_name_span : Span ,
971+ function : FunctionId ,
972+ ) {
973+ if_chain ! {
974+ if !scope. inherits_type( BlockScopeType :: Unsafe ) ;
975+ if let Some ( unsafe_span) = function. unsafe_span( scope. db( ) ) ;
976+ then {
977+ let def_name_span = function. name_span( scope. db( ) ) ;
978+ scope. fancy_error( & format!( "unsafe function `{}` can only be called in an unsafe function or block" ,
979+ fn_name) ,
980+ vec![ Label :: primary( call_name_span, "call to unsafe function" ) ,
981+ Label :: secondary( unsafe_span + def_name_span, format!( "`{}` is defined here as unsafe" , fn_name) ) ] ,
982+ vec![ "Hint: put this call in an `unsafe` block if you're confident that it's safe to use here" . into( ) ] ,
983+ ) ;
984+ }
985+ }
986+ }
987+
966988fn expr_call_self_attribute (
967989 scope : & mut BlockScope ,
968990 func_name : & str ,
@@ -974,6 +996,8 @@ fn expr_call_self_attribute(
974996 let contract = resolve_self ( scope, self_span) ?;
975997
976998 if let Some ( func) = contract. self_function ( scope. db ( ) , func_name) {
999+ check_for_unsafe_call_outside_unsafe ( scope, func_name, name_span, func) ;
1000+
9771001 let sig = func. signature ( scope. root . db ) ;
9781002 validate_named_args (
9791003 scope,
@@ -1013,18 +1037,20 @@ fn expr_call_self_attribute(
10131037
10141038fn expr_call_pure (
10151039 scope : & mut BlockScope ,
1040+ call_name_span : Span ,
10161041 function : FunctionId ,
10171042 args : & Node < Vec < Node < fe:: CallArg > > > ,
10181043) -> Result < ExpressionAttributes , FatalError > {
10191044 assert ! ( function. is_pure( scope. db( ) ) ) ;
10201045
10211046 let fn_name = function. name ( scope. db ( ) ) ;
1022- let name_span = function. name_span ( scope. db ( ) ) ;
1047+ check_for_unsafe_call_outside_unsafe ( scope, & fn_name, call_name_span, function) ;
1048+
10231049 let sig = function. signature ( scope. db ( ) ) ;
10241050 validate_named_args (
10251051 scope,
10261052 & fn_name,
1027- name_span,
1053+ function . name_span ( scope . db ( ) ) ,
10281054 args,
10291055 & sig. params ,
10301056 LabelPolicy :: AllowAnyUnlabeled ,
0 commit comments