Parsing support for thread_local and _Thread_local. We give them the same
semantics as __thread for now.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179424 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 1979bb1..55e2b38 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1848,7 +1848,8 @@
if (DS.getStorageClassSpecLoc().isValid())
Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass);
else
- Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass);
+ Diag(DS.getThreadStorageClassSpecLoc(),
+ diag::err_typename_invalid_storageclass);
DS.ClearStorageClassSpecs();
}
@@ -2181,6 +2182,8 @@
/// 'auto'
/// 'register'
/// [C++] 'mutable'
+/// [C++11] 'thread_local'
+/// [C11] '_Thread_local'
/// [GNU] '__thread'
/// function-specifier: [C99 6.7.4]
/// [C99] 'inline'
@@ -2617,7 +2620,7 @@
PrevSpec, DiagID);
break;
case tok::kw_extern:
- if (DS.isThreadSpecified())
+ if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
PrevSpec, DiagID);
@@ -2627,7 +2630,7 @@
Loc, PrevSpec, DiagID);
break;
case tok::kw_static:
- if (DS.isThreadSpecified())
+ if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
PrevSpec, DiagID);
@@ -2656,7 +2659,16 @@
PrevSpec, DiagID);
break;
case tok::kw___thread:
- isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID);
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_thread_local:
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw__Thread_local:
+ isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
+ Loc, PrevSpec, DiagID);
break;
// function-specifier
@@ -3903,6 +3915,8 @@
case tok::kw_auto:
case tok::kw_register:
case tok::kw___thread:
+ case tok::kw_thread_local:
+ case tok::kw__Thread_local:
// Modules
case tok::kw___module_private__:
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 5e0ef2b..00ca3d8 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -837,11 +837,12 @@
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw___underlying_type:
- case tok::kw_thread_local:
case tok::kw__Decimal32:
case tok::kw__Decimal64:
case tok::kw__Decimal128:
case tok::kw___thread:
+ case tok::kw_thread_local:
+ case tok::kw__Thread_local:
case tok::kw_typeof:
case tok::kw___cdecl:
case tok::kw___stdcall:
@@ -893,7 +894,7 @@
/// function-specifier
/// 'friend'
/// 'typedef'
-/// [C++0x] 'constexpr'
+/// [C++11] 'constexpr'
/// [GNU] attributes declaration-specifiers[opt]
///
/// storage-class-specifier:
@@ -903,6 +904,8 @@
/// 'mutable'
/// 'auto'
/// [GNU] '__thread'
+/// [C++11] 'thread_local'
+/// [C11] '_Thread_local'
///
/// function-specifier:
/// 'inline'
@@ -937,8 +940,8 @@
/// 'void'
/// [GNU] typeof-specifier
/// [GNU] '_Complex'
-/// [C++0x] 'auto' [TODO]
-/// [C++0x] 'decltype' ( expression )
+/// [C++11] 'auto'
+/// [C++11] 'decltype' ( expression )
///
/// type-name:
/// class-name
@@ -1073,6 +1076,8 @@
case tok::kw_mutable:
case tok::kw_auto:
case tok::kw___thread:
+ case tok::kw_thread_local:
+ case tok::kw__Thread_local:
// function-specifier
case tok::kw_inline:
case tok::kw_virtual:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 1ebba3e..d819644 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1141,8 +1141,8 @@
diag::err_invalid_storage_class_in_func_decl);
DS.ClearStorageClassSpecs();
}
- if (DS.isThreadSpecified()) {
- Diag(DS.getThreadSpecLoc(),
+ if (DS.getThreadStorageClassSpec() != DeclSpec::TSCS_unspecified) {
+ Diag(DS.getThreadStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
DS.ClearStorageClassSpecs();
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index e1d55db..7a69eef 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -24,6 +24,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstring>
using namespace clang;
@@ -325,7 +326,7 @@
unsigned DeclSpec::getParsedSpecifiers() const {
unsigned Res = 0;
if (StorageClassSpec != SCS_unspecified ||
- SCS_thread_specified)
+ ThreadStorageClassSpec != TSCS_unspecified)
Res |= PQ_StorageClassSpecifier;
if (TypeQualifiers != TQ_unspecified)
@@ -367,6 +368,16 @@
llvm_unreachable("Unknown typespec!");
}
+const char *DeclSpec::getSpecifierName(DeclSpec::TSCS S) {
+ switch (S) {
+ case DeclSpec::TSCS_unspecified: return "unspecified";
+ case DeclSpec::TSCS___thread: return "__thread";
+ case DeclSpec::TSCS_thread_local: return "thread_local";
+ case DeclSpec::TSCS__Thread_local: return "_Thread_local";
+ }
+ llvm_unreachable("Unknown typespec!");
+}
+
const char *DeclSpec::getSpecifierName(TSW W) {
switch (W) {
case TSW_unspecified: return "unspecified";
@@ -510,16 +521,14 @@
return false;
}
-bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
+bool DeclSpec::SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID) {
- if (SCS_thread_specified) {
- PrevSpec = "__thread";
- DiagID = diag::ext_duplicate_declspec;
- return true;
- }
- SCS_thread_specified = true;
- SCS_threadLoc = Loc;
+ if (ThreadStorageClassSpec != TSCS_unspecified)
+ return BadSpecifier(TSC, (TSCS)ThreadStorageClassSpec, PrevSpec, DiagID);
+
+ ThreadStorageClassSpec = TSC;
+ ThreadStorageClassSpecLoc = Loc;
return false;
}
@@ -923,6 +932,34 @@
}
}
+ // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and
+ // _Thread_local can only appear with the 'static' and 'extern' storage class
+ // specifiers. We also allow __private_extern__ as an extension.
+ if (ThreadStorageClassSpec != TSCS_unspecified) {
+ switch (StorageClassSpec) {
+ case SCS_unspecified:
+ case SCS_extern:
+ case SCS_private_extern:
+ case SCS_static:
+ break;
+ default:
+ if (PP.getSourceManager().isBeforeInTranslationUnit(
+ getThreadStorageClassSpecLoc(), getStorageClassSpecLoc()))
+ Diag(D, getStorageClassSpecLoc(),
+ diag::err_invalid_decl_spec_combination)
+ << DeclSpec::getSpecifierName(getThreadStorageClassSpec())
+ << SourceRange(getThreadStorageClassSpecLoc());
+ else
+ Diag(D, getThreadStorageClassSpecLoc(),
+ diag::err_invalid_decl_spec_combination)
+ << DeclSpec::getSpecifierName(getStorageClassSpec())
+ << SourceRange(getStorageClassSpecLoc());
+ // Discard the thread storage class specifier to recover.
+ ThreadStorageClassSpec = TSCS_unspecified;
+ ThreadStorageClassSpecLoc = SourceLocation();
+ }
+ }
+
// If no type specifier was provided and we're parsing a language where
// the type specifier is not optional, but we got 'auto' as a storage
// class specifier, then assume this is an attempt to use C++0x's 'auto'
@@ -952,16 +989,27 @@
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
- if (isFriendSpecified() && getStorageClassSpec()) {
- DeclSpec::SCS SC = getStorageClassSpec();
- const char *SpecName = getSpecifierName(SC);
+ if (isFriendSpecified() &&
+ (getStorageClassSpec() || getThreadStorageClassSpec())) {
+ SmallString<32> SpecName;
+ SourceLocation SCLoc;
+ FixItHint StorageHint, ThreadHint;
- SourceLocation SCLoc = getStorageClassSpecLoc();
- SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName));
+ if (DeclSpec::SCS SC = getStorageClassSpec()) {
+ SpecName = getSpecifierName(SC);
+ SCLoc = getStorageClassSpecLoc();
+ StorageHint = FixItHint::CreateRemoval(SCLoc);
+ }
+
+ if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) {
+ if (!SpecName.empty()) SpecName += " ";
+ SpecName += getSpecifierName(TSC);
+ SCLoc = getThreadStorageClassSpecLoc();
+ ThreadHint = FixItHint::CreateRemoval(SCLoc);
+ }
Diag(D, SCLoc, diag::err_friend_storage_spec)
- << SpecName
- << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));
+ << SpecName << StorageHint << ThreadHint;
ClearStorageClassSpecs();
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 2db1e2a..a72e74b 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -3348,13 +3348,12 @@
// be a receiver of a class message, this may be a class message send with
// the initial opening bracket '[' missing. Add appropriate completions.
if (AllowNonIdentifiers && !AllowNestedNameSpecifiers &&
+ DS.getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier &&
DS.getTypeSpecType() == DeclSpec::TST_typename &&
- DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
- !DS.isThreadSpecified() && !DS.isExternInLinkageSpec() &&
DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified &&
DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
- DS.getTypeQualifiers() == 0 &&
- S &&
+ !DS.isTypeAltiVecVector() &&
+ S &&
(S->getFlags() & Scope::DeclScope) != 0 &&
(S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope |
Scope::FunctionPrototypeScope |
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c8a5d93..6dfc86f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3182,8 +3182,9 @@
Diag(DS.getStorageClassSpecLoc(), DiagID)
<< DeclSpec::getSpecifierName(SCS);
- if (DS.isThreadSpecified())
- Diag(DS.getThreadSpecLoc(), DiagID) << "__thread";
+ if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec())
+ Diag(DS.getThreadStorageClassSpecLoc(), DiagID)
+ << DeclSpec::getSpecifierName(TSCS);
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
Diag(DS.getConstSpecLoc(), DiagID) << "const";
@@ -4411,8 +4412,6 @@
DiagnoseFunctionSpecifiers(D.getDeclSpec());
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
if (D.getDeclSpec().isConstexprSpecified())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 1;
@@ -4871,12 +4870,17 @@
// lexical context will be different from the semantic context.
NewVD->setLexicalDeclContext(CurContext);
- if (D.getDeclSpec().isThreadSpecified()) {
+ if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
if (NewVD->hasLocalStorage())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global);
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_thread_non_global)
+ << DeclSpec::getSpecifierName(TSCS);
else if (!Context.getTargetInfo().isTLSSupported())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported);
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_thread_unsupported);
else
+ // FIXME: Track which thread specifier was used; they have different
+ // semantics.
NewVD->setThreadSpecified(true);
}
@@ -5836,8 +5840,10 @@
DeclarationName Name = NameInfo.getName();
FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D);
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_invalid_thread)
+ << DeclSpec::getSpecifierName(TSCS);
// Do not allow returning a objc interface by-value.
if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) {
@@ -8235,13 +8241,14 @@
D.getMutableDeclSpec().ClearStorageClassSpecs();
}
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- if (D.getDeclSpec().isConstexprSpecified())
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
+ if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec())
+ Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread)
+ << DeclSpec::getSpecifierName(TSCS);
+ if (DS.isConstexprSpecified())
+ Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 0;
- DiagnoseFunctionSpecifiers(D.getDeclSpec());
+ DiagnoseFunctionSpecifiers(DS);
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
@@ -10361,8 +10368,10 @@
DiagnoseFunctionSpecifiers(D.getDeclSpec());
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_invalid_thread)
+ << DeclSpec::getSpecifierName(TSCS);
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = 0;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 0bea565..8e8ea01 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1679,30 +1679,24 @@
// data members and cannot be applied to names declared const or static,
// and cannot be applied to reference members.
switch (DS.getStorageClassSpec()) {
- case DeclSpec::SCS_unspecified:
- case DeclSpec::SCS_typedef:
- case DeclSpec::SCS_static:
- // FALL THROUGH.
- break;
- case DeclSpec::SCS_mutable:
- if (isFunc) {
- if (DS.getStorageClassSpecLoc().isValid())
- Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function);
- else
- Diag(DS.getThreadSpecLoc(), diag::err_mutable_function);
+ case DeclSpec::SCS_unspecified:
+ case DeclSpec::SCS_typedef:
+ case DeclSpec::SCS_static:
+ break;
+ case DeclSpec::SCS_mutable:
+ if (isFunc) {
+ Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function);
- // FIXME: It would be nicer if the keyword was ignored only for this
- // declarator. Otherwise we could get follow-up errors.
- D.getMutableDeclSpec().ClearStorageClassSpecs();
- }
- break;
- default:
- if (DS.getStorageClassSpecLoc().isValid())
- Diag(DS.getStorageClassSpecLoc(),
- diag::err_storageclass_invalid_for_member);
- else
- Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member);
+ // FIXME: It would be nicer if the keyword was ignored only for this
+ // declarator. Otherwise we could get follow-up errors.
D.getMutableDeclSpec().ClearStorageClassSpecs();
+ }
+ break;
+ default:
+ Diag(DS.getStorageClassSpecLoc(),
+ diag::err_storageclass_invalid_for_member);
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
+ break;
}
bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified ||
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index cb5de9c..48f0dec 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -3190,12 +3190,14 @@
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm)
<< FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc()));
- } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
+ } else if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) {
Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
- << DS.getStorageClassSpec();
- }
- if (D.getDeclSpec().isThreadSpecified())
- Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ << DeclSpec::getSpecifierName(SCS);
+ }
+ if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
+ Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_invalid_thread)
+ << DeclSpec::getSpecifierName(TSCS);
D.getMutableDeclSpec().ClearStorageClassSpecs();
DiagnoseFunctionSpecifiers(D.getDeclSpec());