From 8a89973969d3070736ea7eef24d86dfbc3be5cfc Mon Sep 17 00:00:00 2001 From: Xavier Leroy Date: Thu, 16 Jan 2025 15:02:28 +0100 Subject: [PATCH] Perform basic checks over `[static expr]` array declarators Check that they occur only in function prototypes and only in outermost position. The error messages are those used by clang. --- cparser/Elab.ml | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/cparser/Elab.ml b/cparser/Elab.ml index fbc10692e..0f913fb86 100644 --- a/cparser/Elab.ml +++ b/cparser/Elab.ml @@ -871,7 +871,6 @@ and elab_cvspec env = function and elab_cvspecs env cv_specs = List.fold_left add_attributes [] (List.map (elab_cvspec env) cv_specs) -(* Elaboration of a type declarator. C99 section 6.7.5. *) and elab_return_type loc env ty = match unroll env ty with | TArray _ -> @@ -880,6 +879,8 @@ and elab_return_type loc env ty = error loc "function cannot return function type %a" (print_typ env) ty | _ -> () +(* Elaboration of a type declarator. C99 section 6.7.5. *) + (* The [?fundef] parameter is true if we're elaborating a function definition and false otherwise. When [fundef = true], K&R function declarators are allowed, and the returned environment includes bindings for the @@ -887,7 +888,11 @@ and elab_return_type loc env ty = When [fundef = false], K&R function declarators are rejected and declarations in parameters are not returned. *) -and elab_type_declarator ?(fundef = false) loc env ty = function +(* The [?param] parameter is true if we're elaborating a parameter + of a function prototype, and false otherwise. + This is used for checking 'static' array declarators. *) + +and elab_type_declarator ?(fundef = false) ?(param = false) loc env ty = function | Cabs.JUSTBASE -> ((ty, None), env) | Cabs.ARRAY(d, cv_specs, static, sz) -> @@ -897,6 +902,13 @@ and elab_type_declarator ?(fundef = false) loc env ty = function error loc "array type has incomplete element type %a" (print_typ env) ty; if wrap contains_flex_array_mem loc env ty then warning loc Flexible_array_extensions "%a may not be used as an array element due to flexible array member" (print_typ env) ty; + if static then begin + assert (sz <> None); (* guaranteed by the parser *) + if not param then + error loc "'static' used in array declarator outside of function prototype" + else if d <> Cabs.JUSTBASE then + error loc "'static' used in non-outermost array type derivation" + end; let sz' = match sz with | None -> @@ -913,13 +925,13 @@ and elab_type_declarator ?(fundef = false) loc env ty = function | None -> error loc "size of array is not a compile-time constant"; Some 1L in (* produces better error messages later *) - elab_type_declarator ~fundef loc env (TArray(ty, sz', a)) d + elab_type_declarator ~fundef ~param loc env (TArray(ty, sz', a)) d | Cabs.PTR(cv_specs, d) -> let (ty, a) = get_nontype_attrs env ty in let a = add_attributes a (elab_cvspecs env cv_specs) in if is_function_type env ty && incl_attributes [ARestrict] a then error loc "pointer to function type %a may not be 'restrict' qualified" (print_typ env) ty; - elab_type_declarator ~fundef loc env (TPtr(ty, a)) d + elab_type_declarator ~fundef ~param loc env (TPtr(ty, a)) d | Cabs.PROTO(d, (params, vararg)) -> elab_return_type loc env ty; let (ty, a) = get_nontype_attrs env ty in @@ -935,7 +947,7 @@ and elab_type_declarator ?(fundef = false) loc env ty = function if fundef && d = Cabs.JUSTBASE then ((funty, None), env') else - elab_type_declarator ~fundef loc env funty d + elab_type_declarator ~fundef ~param loc env funty d | Cabs.PROTO_OLD(d, params) -> elab_return_type loc env ty; let (ty, a) = get_nontype_attrs env ty in @@ -950,7 +962,7 @@ and elab_type_declarator ?(fundef = false) loc env ty = function end else begin if params <> [] then fatal_error loc "illegal old-style K&R function definition"; - elab_type_declarator ~fundef loc env funty d + elab_type_declarator ~fundef ~param loc env funty d end (* Elaboration of parameters in a prototype *) @@ -971,7 +983,7 @@ and elab_parameter env (PARAM (spec, id, decl, attr, loc)) = let (sto, inl, noret, tydef, bty, env1) = elab_specifier loc env spec in if tydef then error loc "'typedef' used in function parameter"; - let ((ty, _), _) = elab_type_declarator loc env1 bty decl in + let ((ty, _), _) = elab_type_declarator ~param:true loc env1 bty decl in let ty = add_attributes_type (elab_attributes env attr) ty in if sto <> Storage_default && sto <> Storage_register then error loc (* NB: 'auto' not allowed *) @@ -1014,7 +1026,7 @@ and elab_fundef_name env spec (Name (s, decl, attr, loc)) = error loc "'typedef' is forbidden here"; let id = Env.fresh_ident s in let ((ty, kr_params), env'') = - elab_type_declarator ~fundef:true loc env' bty decl in + elab_type_declarator ~fundef:true ~param:true loc env' bty decl in let a = elab_attributes env attr in (id, sto, inl, noret, add_attributes_type a ty, kr_params, env', env'')