From df6e241614b5cdf30b6a756d40f4d4c5634705b7 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 4 Sep 2020 12:54:07 +0900 Subject: [PATCH] Handle inline functions as static functions --- chibicc.h | 1 + parse.c | 17 +++++++++++------ test/driver.sh | 12 ++++++++++++ test/extern.c | 4 ++++ test/function.c | 6 ++++++ 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/chibicc.h b/chibicc.h index 8e74c72..57c818f 100644 --- a/chibicc.h +++ b/chibicc.h @@ -136,6 +136,7 @@ struct Var { Relocation *rel; // Function + bool is_inline; Var *params; Node *body; Var *locals; diff --git a/parse.c b/parse.c index 1001020..d57671b 100644 --- a/parse.c +++ b/parse.c @@ -56,6 +56,7 @@ typedef struct { bool is_typedef; bool is_static; bool is_extern; + bool is_inline; int align; } VarAttr; @@ -408,7 +409,8 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { while (is_typename(tok)) { // Handle storage class specifiers. - if (equal(tok, "typedef") || equal(tok, "static") || equal(tok, "extern")) { + if (equal(tok, "typedef") || equal(tok, "static") || equal(tok, "extern") || + equal(tok, "inline")) { if (!attr) error_tok(tok, "storage class specifier is not allowed in this context"); @@ -416,11 +418,13 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { attr->is_typedef = true; else if (equal(tok, "static")) attr->is_static = true; - else + else if (equal(tok, "extern")) attr->is_extern = true; + else + attr->is_inline = true; - if (attr->is_typedef && attr->is_static + attr->is_extern > 1) - error_tok(tok, "typedef may not be used together with static or extern"); + if (attr->is_typedef && attr->is_static + attr->is_extern + attr->is_inline > 1) + error_tok(tok, "typedef may not be used together with static, extern or inline"); tok = tok->next; continue; } @@ -1396,7 +1400,7 @@ static bool is_typename(Token *tok) { "void", "_Bool", "char", "short", "int", "long", "struct", "union", "typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned", "const", "volatile", "auto", "register", "restrict", "__restrict", - "__restrict__", "_Noreturn", "float", "double", "typeof", + "__restrict__", "_Noreturn", "float", "double", "typeof", "inline", }; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) @@ -2825,7 +2829,8 @@ static Token *function(Token *tok, Type *basety, VarAttr *attr) { Var *fn = new_gvar(get_ident(ty->name), ty); fn->is_function = true; fn->is_definition = !consume(&tok, tok, ";"); - fn->is_static = attr->is_static; + fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern); + fn->is_inline = attr->is_inline; if (!fn->is_definition) return tok; diff --git a/test/driver.sh b/test/driver.sh index cb1ce8a..ece0de7 100755 --- a/test/driver.sh +++ b/test/driver.sh @@ -109,4 +109,16 @@ $chibicc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \ -m64 -mno-red-zone -w -o /dev/null $tmp/empty.c check 'ignored options' +# Inline functions +echo 'inline void foo() {}' > $tmp/inline1.c +echo 'inline void foo() {}' > $tmp/inline2.c +echo 'int main() { return 0; }' > $tmp/inline3.c +$chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c $tmp/inline3.c +check inline + +echo 'extern inline void foo() {}' > $tmp/inline1.c +echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c +$chibicc -o /dev/null $tmp/inline1.c $tmp/inline2.c +check inline + echo OK diff --git a/test/extern.c b/test/extern.c index a0452e8..1b1351e 100644 --- a/test/extern.c +++ b/test/extern.c @@ -3,6 +3,10 @@ extern int ext1; extern int *ext2; +inline int inline_fn(void) { + return 3; +} + int main() { ASSERT(5, ext1); ASSERT(5, *ext2); diff --git a/test/function.c b/test/function.c index 0fff547..586f10c 100644 --- a/test/function.c +++ b/test/function.c @@ -197,6 +197,10 @@ Ty21 struct_test38(void) { return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; } +inline int inline_fn(void) { + return 3; +} + int main() { ASSERT(3, ret3()); ASSERT(8, add2(3, 5)); @@ -365,5 +369,7 @@ int main() { ASSERT(5, (***add2)(2,3)); + ASSERT(3, inline_fn()); + printf("OK\n"); }