diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-12 22:46:28 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-12 22:46:28 +0000 |
commit | ec64244f5939fa81596fbeddad966cca4b4a4c51 (patch) | |
tree | ae70e896ce070c332787dd2b3be9843972cebef8 /lib/Sema/DeclSpec.cpp | |
parent | 32b5013a7a443ff12cbaa5f3e2f86978179d5e04 (diff) |
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
Diffstat (limited to 'lib/Sema/DeclSpec.cpp')
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index e1d55dbddc..7a69eef2bb 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 @@ bool Declarator::isDeclarationOfFunction() const { 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 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { 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 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, 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 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { } } + // 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 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // 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; + + if (DeclSpec::SCS SC = getStorageClassSpec()) { + SpecName = getSpecifierName(SC); + SCLoc = getStorageClassSpecLoc(); + StorageHint = FixItHint::CreateRemoval(SCLoc); + } - SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); + 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(); } |