aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Li <sparse@chrisli.org>2009-07-10 11:19:22 -0700
committerChristopher Li <sparse@chrisli.org>2009-07-19 02:17:32 +0000
commit8cf99394ee4c08a3ede8ef52cd0b3ce73afcf076 (patch)
tree9b280f75bda93d150735509c86f98a68439b9837
parent37f041aba632b7ffc46eb779df07804d9d7d547a (diff)
downloadsparse-8cf99394ee4c08a3ede8ef52cd0b3ce73afcf076.tar.gz
move extern inline function to file scope
In gcc extern inline function has special meaning. The inline function will never emit stand alone copy of the function. It also allow multiple implementations cross different file. That effectively makes the extern inline has file scope. Signed-off-by: Christopher Li <sparse@chrisli.org>
-rw-r--r--evaluate.c5
-rw-r--r--symbol.c6
-rw-r--r--symbol.h12
-rw-r--r--validation/extern-inline.c23
4 files changed, 40 insertions, 6 deletions
diff --git a/evaluate.c b/evaluate.c
index b63fa367..1ab5ae8b 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -536,11 +536,6 @@ static inline int lvalue_expression(struct expression *expr)
return expr->type == EXPR_PREOP && expr->op == '*';
}
-static inline int is_function(struct symbol *type)
-{
- return type && type->type == SYM_FN;
-}
-
static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *itype)
{
struct expression *index = expr->right;
diff --git a/symbol.c b/symbol.c
index b7bb5af4..cda6bd09 100644
--- a/symbol.c
+++ b/symbol.c
@@ -522,6 +522,8 @@ void check_declaration(struct symbol *sym)
return;
}
if (sym->ctype.modifiers & next->ctype.modifiers & MOD_EXTERN) {
+ if ((sym->ctype.modifiers ^ next->ctype.modifiers) & MOD_INLINE)
+ continue;
sym->same_symbol = next;
return;
}
@@ -558,8 +560,10 @@ void bind_symbol(struct symbol *sym, struct ident *ident, enum namespace ns)
scope = block_scope;
if (ns == NS_SYMBOL && toplevel(scope)) {
unsigned mod = MOD_ADDRESSABLE | MOD_TOPLEVEL;
+
scope = global_scope;
- if (sym->ctype.modifiers & MOD_STATIC) {
+ if (sym->ctype.modifiers & MOD_STATIC ||
+ is_extern_inline(sym)) {
scope = file_scope;
mod = MOD_TOPLEVEL;
}
diff --git a/symbol.h b/symbol.h
index 751dec1c..42d69d60 100644
--- a/symbol.h
+++ b/symbol.h
@@ -340,6 +340,18 @@ static inline int is_void_type(struct symbol *type)
return type == &void_ctype;
}
+static inline int is_function(struct symbol *type)
+{
+ return type && type->type == SYM_FN;
+}
+
+static inline int is_extern_inline(struct symbol *sym)
+{
+ return (sym->ctype.modifiers & MOD_EXTERN) &&
+ (sym->ctype.modifiers & MOD_INLINE) &&
+ is_function(sym->ctype.base_type);
+}
+
static inline int get_sym_type(struct symbol *type)
{
if (type->type == SYM_NODE)
diff --git a/validation/extern-inline.c b/validation/extern-inline.c
new file mode 100644
index 00000000..4f12ac06
--- /dev/null
+++ b/validation/extern-inline.c
@@ -0,0 +1,23 @@
+extern __inline__ int f(int);
+
+extern __inline__ int
+f(int x)
+{
+ return x;
+}
+
+extern int g(int);
+
+extern __inline__ int
+g(int x)
+{
+ return x;
+}
+
+
+/*
+ * check-name: extern inline function
+ * check-command: sparse $file $file
+ * check-description: Extern inline function never emits stand alone copy
+ * of the function. It allows multiple such definitions in different file.
+ */