diff --git a/src/ast/decl.rs b/src/ast/decl.rs index 3425f2d..566a956 100644 --- a/src/ast/decl.rs +++ b/src/ast/decl.rs @@ -13,102 +13,32 @@ impl Ast<'_> { // func_def ::= decl_specs declarator compound_stmt // decl ::= decl_specs init_declarator_list? ";" pub(super) fn external_decl(&mut self) -> Result<(), CompileError> { - let specs = self.decl_specs()?; - if specs.is_empty() { + let decl_specs = self.decl_specs()?; + if decl_specs.is_empty() { return Err(CompileError::InvalidDecl { msg: "外部宣言のパースに失敗しました。型指定子が必要です".to_string(), span: self.current_span(), }); } - let base_ty = TypeRef::from_ds(specs).ok_or_else(|| CompileError::InvalidDecl { - msg: "無効な型指定子です".to_string(), + let base_ty = TypeRef::from_ds(&decl_specs).ok_or_else(|| CompileError::InvalidDecl { + msg: format!("無効な型指定子です: {:?}", decl_specs), span: self.current_span(), })?; let token_pos = self.token_pos; // 関数定義でなかった場合にバックトラックするために保存 - if let Ok(first_decl) = self.declarator(&base_ty) { - // 関数定義の場合: compound_stmt - if let TypeKind::Func { params, return_ty, .. } = &first_decl.ty.kind() { + if let Ok(decl) = self.declarator(&base_ty) { + // 関数定義または関数プロトタイプ宣言の場合 + if let TypeKind::Func { .. } = &decl.ty.kind() { if self.peek_punct("{") { - // プロトタイプ宣言を確認 - if let Some(symbol) = self.find_symbol_mut(&first_decl.name) { - // 関数シンボルが既に存在する場合 - if symbol.is_func() { - if symbol.is_defined() { - // 既に定義済みの場合エラー - return Err(CompileError::InvalidDecl { - msg: format!( - "関数 '{}' が既に定義されています", - first_decl.name - ), - span: first_decl.span, - }); - } else { - // TODO: 抽象宣言子を考慮して型チェックを実装 - // プロトタイプ宣言と定義の型が一致するか確認 - // if symbol.ty != first_decl.ty { - // let span = first_decl.span; - // return Err(CompileError::InvalidDecl { - // msg: format!( - // "関数 '{}' の定義がプロトタイプ宣言と一致しません", - // first_decl.name - // ), - // span, - // }); - // } - } - } else { - // シンボルが関数でない場合エラー - return Err(CompileError::InvalidDecl { - msg: format!("'{}' は関数ではありません", first_decl.name), - span: first_decl.span, - }); - } - symbol.set_defined(true); // 既存のプロトタイプ宣言を定義済みに更新 - } else { - // 関数をシンボルが存在しない場合,新規に関数シンボルを登録 - self.register_func_symbol(&first_decl.name, first_decl.ty, true); - } - let func_id = self.register_func_def(Func::new(&first_decl.name)); // 関数を登録 - self.current_func = Some(func_id); // 現在の関数を設定 - self.push_scope(); // 引数スコープに入る - // 引数を登録 - for param_decl in params { - let symbol_id = self.register_var(param_decl, Some(func_id))?; - self.get_current_func_mut()?.params.push(LocalVar::new(symbol_id)); - } - // 関数の戻り値の型を設定 - self.get_current_func_mut()?.return_ty = *return_ty; - // 関数本体をパース - let func_body = - self.compound_stmt()?.ok_or_else(|| CompileError::InvalidDecl { - msg: "関数本体が必要です".to_string(), - span: self.current_span(), - })?; - if let NodeKind::Block { body } = func_body.kind { - self.get_current_func_mut()?.body = body; - } else { - let span = func_body.span; - return Err(CompileError::InvalidDecl { - msg: "関数本体がブロックではありません。'{' と '}' で囲まれた複合文が必要です" - .to_string(), - span, - }); - } - self.pop_scope(); // 引数スコープを出る - self.calc_current_func_offset()?; // 現在の関数のオフセットとスタックサイズを計算 - self.current_func = None; // 現在の関数をクリア - return Ok(()); + return self.func_def(decl); // 関数定義をパース } else if self.consume_punct(";").is_some() { - // 関数プロトタイプ宣言 - self.register_func_symbol(&first_decl.name, first_decl.ty, false); + self.register_func_symbol(&decl.name, decl.ty, false); // プロトタイプ宣言を登録 return Ok(()); } else { - let span = first_decl.span; return Err(CompileError::InvalidDecl { - msg: "関数の本体が必要です".to_string(), - span, + msg: "関数の本体またはセミコロンが必要です".to_string(), + span: decl.span, }); } } @@ -130,14 +60,90 @@ impl Ast<'_> { Ok(()) } + // 関数定義をパース + fn func_def(&mut self, decl: Decl) -> Result<(), CompileError> { + let TypeKind::Func { params, return_ty, .. } = &decl.ty.kind() else { + return Err(CompileError::InvalidDecl { + msg: "関数型が必要です".to_string(), + span: decl.span, + }); + }; + + // プロトタイプ宣言を検証 + self.validate_func_prototype(&decl)?; + + // 関数シンボルを登録または更新 + if let Some(symbol) = self.find_symbol_mut(&decl.name) { + symbol.set_defined(true); + } else { + self.register_func_symbol(&decl.name, decl.ty, true); + } + + // 関数本体をパース + let func_id = self.register_func_def(Func::new(&decl.name)); + self.current_func = Some(func_id); + self.push_scope(); // 引数スコープに入る + + // パラメータを登録 + for param_decl in params { + let symbol_id = self.register_var(param_decl, Some(func_id))?; + self.get_current_func_mut()?.params.push(LocalVar::new(symbol_id)); + } + + // 戻り値の型を設定 + self.get_current_func_mut()?.return_ty = *return_ty; + + // 関数本体をパース + let func_body = self.compound_stmt()?.ok_or_else(|| CompileError::InvalidDecl { + msg: "関数本体が必要です".to_string(), + span: self.current_span(), + })?; + + let NodeKind::Block { body } = func_body.kind else { + return Err(CompileError::InvalidDecl { + msg: "関数本体がブロックではありません。'{' と '}' で囲まれた複合文が必要です" + .to_string(), + span: func_body.span, + }); + }; + + self.get_current_func_mut()?.body = body; + self.pop_scope(); // 引数スコープを抜ける + self.calc_current_func_offset()?; // ローカル変数のオフセットを計算 + self.current_func = None; + + Ok(()) + } + + // プロトタイプ宣言を検証 + fn validate_func_prototype(&mut self, decl: &Decl) -> Result<(), CompileError> { + if let Some(symbol) = self.find_symbol(&decl.name) { + if !symbol.is_func() { + return Err(CompileError::InvalidDecl { + msg: format!("'{}' は関数ではありません", decl.name), + span: decl.span, + }); + } + if symbol.is_defined() { + return Err(CompileError::InvalidDecl { + msg: format!("関数 '{}' が既に定義されています", decl.name), + span: decl.span, + }); + } + // TODO: 抽象宣言子を考慮して型チェックを実装 + // プロトタイプ宣言と定義の型が一致するか確認 + } + Ok(()) + } + // decl ::= decl_specs init_declarator_list? ";" pub(super) fn decl(&mut self) -> Result>, CompileError> { - let specs = self.decl_specs()?; - if specs.is_empty() { + let decl_specs = self.decl_specs()?; + if decl_specs.is_empty() { return Ok(None); } - let base_ty = TypeRef::from_ds(specs).ok_or_else(|| CompileError::InvalidDecl { - msg: "無効な型指定子です".to_string(), + let base_ty = TypeRef::from_ds(&decl_specs).ok_or_else(|| CompileError::InvalidDecl { + msg: format!("無効な型指定子です: {:?}", decl_specs), span: self.current_span(), })?; let decls = self.init_declarator_list(&base_ty)?; @@ -147,11 +153,11 @@ impl Ast<'_> { // decl_specs ::= decl_spec+ pub(super) fn decl_specs(&mut self) -> Result, CompileError> { - let mut specs = Vec::new(); - while let Some(spec) = self.decl_spec()? { - specs.push(spec); + let mut decl_specs = Vec::new(); + while let Some(decl_spec) = self.decl_spec()? { + decl_specs.push(decl_spec); } - Ok(specs) + Ok(decl_specs) } // decl_spec ::= storage_class_spec | type_spec | type_qual | func_spec @@ -369,14 +375,15 @@ impl Ast<'_> { // struct_decl ::= spec_qual_list struct_declarator_list? ";" fn struct_decl(&mut self) -> Result>, CompileError> { - let specs = self.spec_qual_list()?; - if specs.is_empty() { + let type_spec_quals = self.spec_qual_list()?; + if type_spec_quals.is_empty() { return Ok(None); } - let base_ty = TypeRef::from_tsq(specs).ok_or_else(|| CompileError::InvalidDecl { - msg: "無効な型指定子です".to_string(), - span: self.current_span(), - })?; + let base_ty = + TypeRef::from_tsq(&type_spec_quals).ok_or_else(|| CompileError::InvalidDecl { + msg: format!("無効な型指定子です: {:?}", type_spec_quals), + span: self.current_span(), + })?; let members = self.struct_declarator_list(&base_ty)?; self.expect_punct(";")?; Ok(Some(members)) @@ -466,12 +473,13 @@ impl Ast<'_> { ) -> Result { // 既存の列挙体タグを検索 if let Some(tag) = self.find_tag(&enum_name) { - return Ok(tag.ty.kind()); + Ok(tag.ty.kind()) + } else { + Err(CompileError::InvalidDecl { + msg: format!("列挙体 '{}' が見つかりません", enum_name), + span, + }) } - Err(CompileError::InvalidDecl { - msg: format!("列挙体 '{}' が見つかりません", enum_name), - span, - }) } // enum_list ::= enumerator ( "," enumerator )* @@ -526,11 +534,11 @@ impl Ast<'_> { // spec_qual_list ::= type_spec_qual+ fn spec_qual_list(&mut self) -> Result, CompileError> { - let mut specs = Vec::new(); - while let Some(spec) = self.type_spec_qual()? { - specs.push(spec); + let mut type_spec_quals = Vec::new(); + while let Some(type_spec_qual) = self.type_spec_qual()? { + type_spec_quals.push(type_spec_qual); } - Ok(specs) + Ok(type_spec_quals) } // type_spec_qual ::= type_spec | type_qual @@ -538,8 +546,8 @@ impl Ast<'_> { if let Some(spec) = self.type_spec()? { return Ok(Some(TypeSpecQual::TypeSpec(spec))); } - if let Some(qual) = self.type_qual() { - return Ok(Some(TypeSpecQual::TypeQual(qual))); + if let Some(type_qual) = self.type_qual() { + return Ok(Some(TypeSpecQual::TypeQual(type_qual))); } Ok(None) } @@ -548,7 +556,7 @@ impl Ast<'_> { fn type_qual(&mut self) -> Option { TypeQualKind::all() .into_iter() - .find(|qual| self.consume_keyword(&qual.to_string()).is_some()) + .find(|type_qual| self.consume_keyword(&type_qual.to_string()).is_some()) } // func_spec ::= "inline" @@ -558,25 +566,25 @@ impl Ast<'_> { // type_qual_list ::= type_qual* fn type_qual_list(&mut self) -> Vec { - let mut quals = Vec::new(); - while let Some(qual) = self.type_qual() { - quals.push(qual); + let mut type_quals = Vec::new(); + while let Some(type_qual) = self.type_qual() { + type_quals.push(type_qual); } - quals + type_quals } // ptr ::= "*" type_qual_list? ptr? fn ptr(&mut self, base_ty: &TypeRef) -> TypeRef { - if self.consume_punct("*").is_some() { - self.type_qual_list(); // 現状は型修飾子を無視 - let ptr_type = TypeRef::register( - TypeKind::Ptr { to: TypeRef::register(base_ty.kind(), base_ty.attr(), None) }, - TypeAttr::default(), - base_ty.storage_class(), + let mut current_ty = *base_ty; + while self.consume_punct("*").is_some() { + let type_quals = self.type_qual_list(); + current_ty = TypeRef::register( + TypeKind::Ptr { to: TypeRef::register(current_ty.kind(), current_ty.attr(), None) }, + TypeAttr::from_type_quals(&type_quals), + current_ty.storage_class(), ); - return self.ptr(&ptr_type); } - *base_ty + current_ty } // declarator ::= ptr? direct_declarator @@ -590,30 +598,31 @@ impl Ast<'_> { // | direct_declarator "[" type_qual_list? assign_expr? "]" // | direct_declarator "(" param_type_list ")" fn direct_declarator(&mut self, base_ty: &TypeRef) -> Result { - let span; - let name = if let Some(paren_span) = self.consume_punct("(") { - span = paren_span; - let inner_var = self.declarator(base_ty)?; + if let Some(paren_span) = self.consume_punct("(") { + let placeholder = TypeRef::default(); // プレースホルダーを使って内側の型を一時的に表現 + let inner_decl = self.declarator(&placeholder)?; self.expect_punct(")")?; - inner_var.name - } else if let Some((name, ident_span)) = self.consume_ident() { - span = ident_span; - name + let suffix_ty = self.direct_declarator_suffix(base_ty)?; // 外側のsuffixを先にパース + // プレースホルダーをsuffix_tyで置き換え + let final_ty = inner_decl.ty.replace_type(placeholder, suffix_ty); + Ok(Decl::new(inner_decl.name, final_ty, paren_span)) + } else if let Some((ident_name, ident_span)) = self.consume_ident() { + // 識別子の場合は普通にsuffixを適用 + let final_ty = self.direct_declarator_suffix(base_ty)?; + Ok(Decl::new(ident_name, final_ty, ident_span)) } else { - return Err(CompileError::InvalidDecl { + Err(CompileError::InvalidDecl { msg: "識別子または括弧で囲まれた宣言子が必要です".to_string(), span: self.current_span(), - }); - }; - let final_ty = self.parse_postfix_declarators(base_ty)?; - Ok(Decl::new(name, final_ty, span)) + }) + } } // 右結合で解析 - fn parse_postfix_declarators(&mut self, base_ty: &TypeRef) -> Result { + fn direct_declarator_suffix(&mut self, base_ty: &TypeRef) -> Result { // "[" type_qual_list? assign_expr? "]" if self.consume_punct("[").is_some() { - self.type_qual_list(); // 現状は型修飾子を無視 + let type_quals = self.type_qual_list(); let array_size = if self.peek_punct("]") { 0 } else { @@ -624,11 +633,11 @@ impl Ast<'_> { Self::eval_const_expr(&assign_expr)? as usize }; self.expect_punct("]")?; - let inner_ty = self.parse_postfix_declarators(base_ty)?; + let inner_ty = self.direct_declarator_suffix(base_ty)?; let elem_ty = TypeRef::register(inner_ty.kind(), inner_ty.attr(), None); // 要素型のストレージクラスはなし Ok(TypeRef::register( TypeKind::Array { base: elem_ty, size: array_size }, - TypeAttr::default(), + TypeAttr::from_type_quals(&type_quals), inner_ty.storage_class(), )) } @@ -644,8 +653,8 @@ impl Ast<'_> { self.expect_punct(")")?; result }; - let inner_ty = self.parse_postfix_declarators(base_ty)?; - let return_ty = TypeRef::register(inner_ty.kind(), inner_ty.attr(), None); // 戻り値型のストレージクラスはなし + let inner_ty = self.direct_declarator_suffix(base_ty)?; + let return_ty = TypeRef::register(inner_ty.kind(), inner_ty.attr(), None); // 戻り値型にストレージクラスは付けられない Ok(TypeRef::register( TypeKind::Func { return_ty, params, is_variadic }, TypeAttr::default(), @@ -680,16 +689,16 @@ impl Ast<'_> { // param_decl ::= decl_specs declarator // | decl_specs abstract_declarator? fn param_decl(&mut self) -> Result { - let specs = self.decl_specs()?; - if specs.is_empty() { + let decl_specs = self.decl_specs()?; + if decl_specs.is_empty() { return Err(CompileError::InvalidDecl { msg: "パラメータ宣言には型指定子が必要です".to_string(), span: self.current_span(), }); } - let base_ty = TypeRef::from_ds(specs).ok_or_else(|| CompileError::InvalidDecl { - msg: "無効な型指定子です".to_string(), + let base_ty = TypeRef::from_ds(&decl_specs).ok_or_else(|| CompileError::InvalidDecl { + msg: format!("無効な型指定子です: {:?}", decl_specs), span: self.current_span(), })?; @@ -717,17 +726,18 @@ impl Ast<'_> { // type_name ::= spec_qual_list abst_declarator? pub(super) fn type_name(&mut self) -> Result { - let specs = self.spec_qual_list()?; - if specs.is_empty() { + let type_spec_quals = self.spec_qual_list()?; + if type_spec_quals.is_empty() { return Err(CompileError::InvalidDecl { msg: "無効な型名です".to_string(), span: self.current_span(), }); } - let base_ty = TypeRef::from_tsq(specs).ok_or_else(|| CompileError::InvalidDecl { - msg: "無効な型指定子です".to_string(), - span: self.current_span(), - })?; + let base_ty = + TypeRef::from_tsq(&type_spec_quals).ok_or_else(|| CompileError::InvalidDecl { + msg: format!("無効な型指定子です: {:?}", type_spec_quals), + span: self.current_span(), + })?; if let Ok(abst_ty) = self.abst_declarator(&base_ty) { return Ok(abst_ty); } @@ -756,25 +766,26 @@ impl Ast<'_> { // | direct_abst_declarator "[" type_qual_list? assign_expr? "]" // | direct_abst_declarator "(" param_type_list ")" fn direct_abst_declarator(&mut self, base_ty: &TypeRef) -> Result { - let mut current_ty = if self.consume_punct("(").is_some() { - let inner_ty = self.abst_declarator(base_ty)?; + if self.consume_punct("(").is_some() { + let placeholder = TypeRef::default(); // プレースホルダーを使って内側の型を一時的に表現 + let inner_ty = self.abst_declarator(&placeholder)?; self.expect_punct(")")?; - inner_ty + let suffix_ty = self.direct_abst_declarator_suffix(base_ty)?; // 外側のsuffixを先にパース + // プレースホルダーをsuffix_tyで置き換え + Ok(inner_ty.replace_type(placeholder, suffix_ty)) } else { - *base_ty - }; - current_ty = self.parse_abst_postfix_declarators(¤t_ty)?; - Ok(current_ty) + self.direct_abst_declarator_suffix(base_ty) + } } // 右結合で解析 - fn parse_abst_postfix_declarators( + fn direct_abst_declarator_suffix( &mut self, base_ty: &TypeRef, ) -> Result { // "[" type_qual_list? assign_expr? "]" if self.consume_punct("[").is_some() { - self.type_qual_list(); // 現状は型修飾子を無視 + let type_quals = self.type_qual_list(); let array_size = if self.peek_punct("]") { 0 } else { @@ -785,10 +796,10 @@ impl Ast<'_> { Self::eval_const_expr(&assign_expr)? as usize }; self.expect_punct("]")?; - let inner_ty = self.parse_abst_postfix_declarators(base_ty)?; + let inner_ty = self.direct_abst_declarator_suffix(base_ty)?; Ok(TypeRef::register( TypeKind::Array { base: inner_ty, size: array_size }, - TypeAttr::default(), + TypeAttr::from_type_quals(&type_quals), None, )) } @@ -804,7 +815,7 @@ impl Ast<'_> { self.expect_punct(")")?; result }; - let inner_ty = self.parse_abst_postfix_declarators(base_ty)?; + let inner_ty = self.direct_abst_declarator_suffix(base_ty)?; Ok(TypeRef::register( TypeKind::Func { return_ty: inner_ty, params, is_variadic }, TypeAttr::default(), diff --git a/src/types.rs b/src/types.rs index 3db58d2..79582f3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -34,6 +34,16 @@ impl fmt::Debug for TypeAttr { } } +impl TypeAttr { + pub(crate) fn from_type_quals(quals: &[TypeQualKind]) -> Self { + TypeAttr { + is_const: quals.contains(&TypeQualKind::Const), + is_volatile: quals.contains(&TypeQualKind::Volatile), + is_restrict: quals.contains(&TypeQualKind::Restrict), + } + } +} + #[derive(Clone, PartialEq, Eq)] pub(crate) struct TypeData { kind: TypeKind, diff --git a/src/types/type_ref.rs b/src/types/type_ref.rs index 13a5529..cef6e5f 100644 --- a/src/types/type_ref.rs +++ b/src/types/type_ref.rs @@ -115,7 +115,7 @@ impl TypeRef { None } - pub(crate) fn from_ds(decl_specs: Vec) -> Option { + pub(crate) fn from_ds(decl_specs: &[DeclSpec]) -> Option { let mut attr = TypeAttr::default(); let mut ty_ref: Option = None; let mut storage_class = None; @@ -130,7 +130,7 @@ impl TypeRef { if ty_ref.is_some() { return None; // すでに型指定子があった場合は無効 } - ty_ref = Some(ty); + ty_ref = Some(*ty); } DeclSpec::StorageClassSpec(sc_kind) => { if storage_class.is_some() { @@ -148,13 +148,13 @@ impl TypeRef { is_volatile: attr.is_volatile || ty.attr().is_volatile, is_restrict: attr.is_restrict || ty.attr().is_restrict, }; - Some(TypeRef::register(ty.kind(), merged_attr, storage_class)) + Some(TypeRef::register(ty.kind(), merged_attr, storage_class.cloned())) } else { None } } - pub(crate) fn from_tsq(type_spec_quals: Vec) -> Option { + pub(crate) fn from_tsq(type_spec_quals: &[TypeSpecQual]) -> Option { let mut attr = TypeAttr::default(); let mut ty_ref: Option = None; for spec in type_spec_quals { @@ -168,7 +168,7 @@ impl TypeRef { if ty_ref.is_some() { return None; // すでに型指定子があった場合は無効 } - ty_ref = Some(ty); + ty_ref = Some(*ty); } } } @@ -216,4 +216,38 @@ impl TypeRef { self.set(data); *self } + + /// 型の中の特定の型を別の型で置き換える + /// + /// 宣言子パースで使用される。括弧で囲まれた宣言子の場合、 + /// プレースホルダー型で内側をパースした後、このメソッドで + /// プレースホルダーを実際の型に置き換える。 + pub(crate) fn replace_type(self, target: TypeRef, replacement: TypeRef) -> TypeRef { + if self == target { + return replacement; + } + match self.kind() { + TypeKind::Ptr { to } => { + let new_to = to.replace_type(target, replacement); + TypeRef::register(TypeKind::Ptr { to: new_to }, self.attr(), self.storage_class()) + } + TypeKind::Array { base, size } => { + let new_base = base.replace_type(target, replacement); + TypeRef::register( + TypeKind::Array { base: new_base, size }, + self.attr(), + self.storage_class(), + ) + } + TypeKind::Func { return_ty, params, is_variadic } => { + let new_return = return_ty.replace_type(target, replacement); + TypeRef::register( + TypeKind::Func { return_ty: new_return, params, is_variadic }, + self.attr(), + self.storage_class(), + ) + } + _ => self, + } + } } diff --git a/test/inline.sh b/test/inline.sh index cb74ea7..8775687 100755 --- a/test/inline.sh +++ b/test/inline.sh @@ -356,3 +356,38 @@ assert_inline 67 'char *s = "\x41\x42\x43"; return s[2];' assert_inline 65 'char *s = "\101\x42\103"; return s[0];' # A assert_inline 66 'char *s = "\101\x42\103"; return s[1];' # B assert_inline 67 'char *s = "\101\x42\103"; return s[2];' # C + +# ============================================================================= +# 関数ポインタ +# ============================================================================= + +# 基本的な関数ポインタの宣言 +assert_inline 0 'int (*fp)(int, int); return 0;' + +# 関数ポインタを返す関数の宣言 +assert_inline 0 'int (*get_func(int x))(int, int); return 0;' + +# 関数ポインタを返す関数ポインタの宣言 +assert_inline 0 'int (*(*fp)(int))(double); return 0;' + +# 関数ポインタの配列の宣言 +assert_inline 0 'int (*arr[5])(int, int); return 0;' + +# 複雑な関数ポインタ宣言 +assert_inline 0 'int (*(*(*p)[10])(int))(double); return 0;' + +# ============================================================================= +# 抽象宣言子(Abstract Declarator)の関数ポインタ +# ============================================================================= + +# sizeof演算子で抽象宣言子を使用 +assert_inline 8 'return sizeof(int (*)(int, int));' + +# 関数ポインタを返す関数の型のサイズ +assert_inline 8 'return sizeof(int (*(*)(int))(double));' + +# 関数ポインタの配列の型のサイズ +assert_inline 40 'return sizeof(int (*[5])(int, int));' + +# キャストで抽象宣言子を使用(型チェックのみ) +assert_inline 0 'int (*fp)(int, int); fp = (int (*)(int, int))0; return 0;'