diff options
Diffstat (limited to 'gcc/c-decl.c')
-rw-r--r-- | gcc/c-decl.c | 93 |
1 files changed, 75 insertions, 18 deletions
diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 8825db1..0890a2a 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3350,9 +3350,19 @@ start_decl (declarator, declspecs, initialized, attributes) /* ANSI specifies that a tentative definition which is not merged with a non-tentative definition behaves exactly like a definition with an initializer equal to zero. (Section 3.7.2) - -fno-common gives strict ANSI behavior. Usually you don't want it. - This matters only for variables with external linkage. */ - if (!initialized && (! flag_no_common || ! TREE_PUBLIC (decl))) + + -fno-common gives strict ANSI behavior, though this tends to break + a large body of code that grew up without this rule. + + Thread-local variables are never common, since there's no entrenched + body of code to break, and it allows more efficient variable references + in the presense of dynamic linking. */ + + if (TREE_CODE (decl) == VAR_DECL + && !initialized + && TREE_PUBLIC (decl) + && !DECL_THREAD_LOCAL (decl) + && !flag_no_common) DECL_COMMON (decl) = 1; /* Set attributes here so if duplicate decl, will have proper attributes. */ @@ -3933,7 +3943,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) enum rid i = C_RID_CODE (id); if ((int) i <= (int) RID_LAST_MODIFIER) { - if (i == RID_LONG && (specbits & (1 << (int) i))) + if (i == RID_LONG && (specbits & (1 << (int) RID_LONG))) { if (longlong) error ("`long long long' is too long for GCC"); @@ -3947,6 +3957,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) } else if (specbits & (1 << (int) i)) pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + + /* Diagnose "__thread extern". Recall that this list + is in the reverse order seen in the text. */ + if (i == RID_THREAD + && (specbits & (1 << (int) RID_EXTERN + | 1 << (int) RID_STATIC))) + { + if (specbits & 1 << (int) RID_EXTERN) + error ("`__thread' before `extern'"); + else + error ("`__thread' before `static'"); + } + specbits |= 1 << (int) i; goto found; } @@ -4196,6 +4219,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) if (specbits & 1 << (int) RID_REGISTER) nclasses++; if (specbits & 1 << (int) RID_TYPEDEF) nclasses++; + /* "static __thread" and "extern __thread" are allowed. */ + if ((specbits & (1 << (int) RID_THREAD + | 1 << (int) RID_STATIC + | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD)) + nclasses++; + /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ @@ -4205,7 +4234,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) && (specbits & ((1 << (int) RID_REGISTER) | (1 << (int) RID_AUTO) - | (1 << (int) RID_TYPEDEF)))) + | (1 << (int) RID_TYPEDEF) + | (1 << (int) RID_THREAD)))) { if (specbits & 1 << (int) RID_AUTO && (pedantic || current_binding_level == global_binding_level)) @@ -4214,8 +4244,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) error ("function definition declared `register'"); if (specbits & 1 << (int) RID_TYPEDEF) error ("function definition declared `typedef'"); + if (specbits & 1 << (int) RID_THREAD) + error ("function definition declared `__thread'"); specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) - | (1 << (int) RID_AUTO)); + | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD)); } else if (decl_context != NORMAL && nclasses > 0) { @@ -4238,7 +4270,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) } specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER) | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC) - | (1 << (int) RID_EXTERN)); + | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD)); } } else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag) @@ -4249,12 +4281,25 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) else error ("`%s' has both `extern' and initializer", name); } - else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag - && current_binding_level != global_binding_level) - error ("nested function `%s' declared `extern'", name); - else if (current_binding_level == global_binding_level - && specbits & (1 << (int) RID_AUTO)) - error ("top-level declaration of `%s' specifies `auto'", name); + else if (current_binding_level == global_binding_level) + { + if (specbits & 1 << (int) RID_AUTO) + error ("top-level declaration of `%s' specifies `auto'", name); + } + else + { + if (specbits & 1 << (int) RID_EXTERN && funcdef_flag) + error ("nested function `%s' declared `extern'", name); + else if ((specbits & (1 << (int) RID_THREAD + | 1 << (int) RID_EXTERN + | 1 << (int) RID_STATIC)) + == (1 << (int) RID_THREAD)) + { + error ("function-scope `%s' implicitly auto and declared `__thread'", + name); + specbits &= ~(1 << (int) RID_THREAD); + } + } } /* Now figure out the structure of the declarator proper. @@ -4842,6 +4887,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) pedwarn ("invalid storage class for function `%s'", name); if (specbits & (1 << (int) RID_REGISTER)) error ("invalid storage class for function `%s'", name); + if (specbits & (1 << (int) RID_THREAD)) + error ("invalid storage class for function `%s'", name); /* Function declaration not at top level. Storage classes other than `extern' are not allowed and `extern' makes no difference. */ @@ -4934,22 +4981,32 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) pedwarn_with_decl (decl, "variable `%s' declared `inline'"); DECL_EXTERNAL (decl) = extern_ref; + /* At top level, the presence of a `static' or `register' storage class specifier, or the absence of all storage class specifiers makes this declaration a definition (perhaps tentative). Also, the absence of both `static' and `register' makes it public. */ if (current_binding_level == global_binding_level) { - TREE_PUBLIC (decl) - = !(specbits - & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER))); - TREE_STATIC (decl) = ! DECL_EXTERNAL (decl); + TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC) + | (1 << (int) RID_REGISTER))); + TREE_STATIC (decl) = !extern_ref; } /* Not at top level, only `static' makes a static definition. */ else { TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0; - TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); + TREE_PUBLIC (decl) = extern_ref; + } + + if (specbits & 1 << (int) RID_THREAD) + { + if (targetm.have_tls) + DECL_THREAD_LOCAL (decl) = 1; + else + /* A mere warning is sure to result in improper semantics + at runtime. Don't bother to allow this to compile. */ + error ("thread-local storage not supported for this target"); } } |