@@ -13,6 +13,7 @@ use rustc_hir::{
1313use rustc_hir_analysis:: astconv:: AstConv ;
1414use rustc_infer:: traits:: { self , StatementAsExpression } ;
1515use rustc_middle:: lint:: in_external_macro;
16+ use rustc_middle:: ty:: print:: with_no_trimmed_paths;
1617use rustc_middle:: ty:: {
1718 self , suggest_constraining_type_params, Binder , DefIdTree , IsSuggestable , ToPredicate , Ty ,
1819 TypeVisitable ,
@@ -704,10 +705,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
704705 }
705706 }
706707 hir:: FnRetTy :: Return ( ty) => {
708+ let span = ty. span ;
709+
710+ if let hir:: TyKind :: OpaqueDef ( item_id, ..) = ty. kind
711+ && let hir:: Node :: Item ( hir:: Item {
712+ kind : hir:: ItemKind :: OpaqueTy ( op_ty) ,
713+ ..
714+ } ) = self . tcx . hir ( ) . get ( item_id. hir_id ( ) )
715+ && let hir:: OpaqueTy {
716+ bounds : [ bound] , ..
717+ } = op_ty
718+ && let hir:: GenericBound :: LangItemTrait (
719+ hir:: LangItem :: Future , _, _, generic_args) = bound
720+ && let hir:: GenericArgs { bindings : [ ty_binding] , .. } = generic_args
721+ && let hir:: TypeBinding { kind, .. } = ty_binding
722+ && let hir:: TypeBindingKind :: Equality { term } = kind
723+ && let hir:: Term :: Ty ( term_ty) = term {
724+ // Check if async function's return type was omitted.
725+ // Don't emit suggestions if the found type is `impl Future<...>`.
726+ debug ! ( "suggest_missing_return_type: found = {:?}" , found) ;
727+ if found. is_suggestable ( self . tcx , false ) {
728+ if term_ty. span . is_empty ( ) {
729+ err. subdiagnostic ( AddReturnTypeSuggestion :: Add { span, found : found. to_string ( ) } ) ;
730+ return true ;
731+ } else {
732+ err. subdiagnostic ( ExpectedReturnTypeLabel :: Other { span, expected } ) ;
733+ }
734+ }
735+ }
736+
707737 // Only point to return type if the expected type is the return type, as if they
708738 // are not, the expectation must have been caused by something else.
709739 debug ! ( "suggest_missing_return_type: return type {:?} node {:?}" , ty, ty. kind) ;
710- let span = ty. span ;
711740 let ty = self . astconv ( ) . ast_ty_to_ty ( ty) ;
712741 debug ! ( "suggest_missing_return_type: return type {:?}" , ty) ;
713742 debug ! ( "suggest_missing_return_type: expected type {:?}" , ty) ;
@@ -1244,6 +1273,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12441273 }
12451274 }
12461275
1276+ /// Suggest providing `std::ptr::null()` or `std::ptr::null_mut()` if they
1277+ /// pass in a literal 0 to an raw pointer.
1278+ #[ instrument( skip( self , err) ) ]
1279+ pub ( crate ) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg (
1280+ & self ,
1281+ err : & mut Diagnostic ,
1282+ expr : & hir:: Expr < ' _ > ,
1283+ expected_ty : Ty < ' tcx > ,
1284+ ) -> bool {
1285+ // Expected type needs to be a raw pointer.
1286+ let ty:: RawPtr ( ty:: TypeAndMut { mutbl, .. } ) = expected_ty. kind ( ) else {
1287+ return false ;
1288+ } ;
1289+
1290+ // Provided expression needs to be a literal `0`.
1291+ let ExprKind :: Lit ( Spanned {
1292+ node : rustc_ast:: LitKind :: Int ( 0 , _) ,
1293+ span,
1294+ } ) = expr. kind else {
1295+ return false ;
1296+ } ;
1297+
1298+ // We need to find a null pointer symbol to suggest
1299+ let null_sym = match mutbl {
1300+ hir:: Mutability :: Not => sym:: ptr_null,
1301+ hir:: Mutability :: Mut => sym:: ptr_null_mut,
1302+ } ;
1303+ let Some ( null_did) = self . tcx . get_diagnostic_item ( null_sym) else {
1304+ return false ;
1305+ } ;
1306+ let null_path_str = with_no_trimmed_paths ! ( self . tcx. def_path_str( null_did) ) ;
1307+
1308+ // We have satisfied all requirements to provide a suggestion. Emit it.
1309+ err. span_suggestion (
1310+ span,
1311+ format ! ( "if you meant to create a null pointer, use `{null_path_str}()`" ) ,
1312+ null_path_str + "()" ,
1313+ Applicability :: MachineApplicable ,
1314+ ) ;
1315+
1316+ true
1317+ }
1318+
12471319 pub ( crate ) fn suggest_associated_const (
12481320 & self ,
12491321 err : & mut Diagnostic ,
0 commit comments