зеркало из https://github.com/microsoft/clang-1.git
Annotate flavor of TLS variable (statically or dynamically initialized) onto the AST.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179447 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
84083b74ab
Коммит
38afbc7361
|
@ -641,6 +641,13 @@ public:
|
||||||
ListInit ///< Direct list-initialization (C++11)
|
ListInit ///< Direct list-initialization (C++11)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Kinds of thread-local storage.
|
||||||
|
enum TLSKind {
|
||||||
|
TLS_None, ///< Not a TLS variable.
|
||||||
|
TLS_Static, ///< TLS with a known-constant initializer.
|
||||||
|
TLS_Dynamic ///< TLS with a dynamic initializer.
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// \brief Placeholder type used in Init to denote an unparsed C++ default
|
/// \brief Placeholder type used in Init to denote an unparsed C++ default
|
||||||
/// argument.
|
/// argument.
|
||||||
|
@ -664,7 +671,7 @@ private:
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
|
|
||||||
unsigned SClass : 3;
|
unsigned SClass : 3;
|
||||||
unsigned ThreadSpecified : 1;
|
unsigned TLSKind : 2;
|
||||||
unsigned InitStyle : 2;
|
unsigned InitStyle : 2;
|
||||||
|
|
||||||
/// \brief Whether this variable is the exception variable in a C++ catch
|
/// \brief Whether this variable is the exception variable in a C++ catch
|
||||||
|
@ -687,7 +694,7 @@ private:
|
||||||
/// \brief Whether this variable is (C++0x) constexpr.
|
/// \brief Whether this variable is (C++0x) constexpr.
|
||||||
unsigned IsConstexpr : 1;
|
unsigned IsConstexpr : 1;
|
||||||
};
|
};
|
||||||
enum { NumVarDeclBits = 14 };
|
enum { NumVarDeclBits = 12 };
|
||||||
|
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class StmtIteratorBase;
|
friend class StmtIteratorBase;
|
||||||
|
@ -771,9 +778,9 @@ public:
|
||||||
}
|
}
|
||||||
void setStorageClass(StorageClass SC);
|
void setStorageClass(StorageClass SC);
|
||||||
|
|
||||||
void setThreadSpecified(bool T) { VarDeclBits.ThreadSpecified = T; }
|
void setTLSKind(TLSKind TLS) { VarDeclBits.TLSKind = TLS; }
|
||||||
bool isThreadSpecified() const {
|
TLSKind getTLSKind() const {
|
||||||
return VarDeclBits.ThreadSpecified;
|
return static_cast<TLSKind>(VarDeclBits.TLSKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// hasLocalStorage - Returns true if a variable with function scope
|
/// hasLocalStorage - Returns true if a variable with function scope
|
||||||
|
|
|
@ -3369,6 +3369,9 @@ def err_non_thread_thread : Error<
|
||||||
"non-thread-local declaration of %0 follows thread-local declaration">;
|
"non-thread-local declaration of %0 follows thread-local declaration">;
|
||||||
def err_thread_non_thread : Error<
|
def err_thread_non_thread : Error<
|
||||||
"thread-local declaration of %0 follows non-thread-local declaration">;
|
"thread-local declaration of %0 follows non-thread-local declaration">;
|
||||||
|
def err_thread_thread_different_kind : Error<
|
||||||
|
"thread-local declaration of %0 with %select{static|dynamic}1 initialization "
|
||||||
|
"follows declaration with %select{dynamic|static}1 initialization">;
|
||||||
def err_redefinition_different_type : Error<
|
def err_redefinition_different_type : Error<
|
||||||
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
|
"redefinition of %0 with a different type%diff{: $ vs $|}1,2">;
|
||||||
def err_redefinition_different_kind : Error<
|
def err_redefinition_different_kind : Error<
|
||||||
|
|
|
@ -853,8 +853,11 @@ void ASTDumper::VisitVarDecl(const VarDecl *D) {
|
||||||
StorageClass SC = D->getStorageClass();
|
StorageClass SC = D->getStorageClass();
|
||||||
if (SC != SC_None)
|
if (SC != SC_None)
|
||||||
OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
|
OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
|
||||||
if (D->isThreadSpecified())
|
switch (D->getTLSKind()) {
|
||||||
OS << " __thread";
|
case VarDecl::TLS_None: break;
|
||||||
|
case VarDecl::TLS_Static: OS << " tls"; break;
|
||||||
|
case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break;
|
||||||
|
}
|
||||||
if (D->isModulePrivate())
|
if (D->isModulePrivate())
|
||||||
OS << " __module_private__";
|
OS << " __module_private__";
|
||||||
if (D->isNRVOVariable())
|
if (D->isNRVOVariable())
|
||||||
|
|
|
@ -641,14 +641,25 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
|
||||||
|
|
||||||
|
|
||||||
void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
void DeclPrinter::VisitVarDecl(VarDecl *D) {
|
||||||
StorageClass SC = D->getStorageClass();
|
if (!Policy.SuppressSpecifiers) {
|
||||||
if (!Policy.SuppressSpecifiers && SC != SC_None)
|
StorageClass SC = D->getStorageClass();
|
||||||
Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
|
if (SC != SC_None)
|
||||||
|
Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
|
||||||
|
|
||||||
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
|
switch (D->getTLSKind()) {
|
||||||
Out << "__thread ";
|
case VarDecl::TLS_None:
|
||||||
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
|
break;
|
||||||
Out << "__module_private__ ";
|
case VarDecl::TLS_Static:
|
||||||
|
Out << "_Thread_local ";
|
||||||
|
break;
|
||||||
|
case VarDecl::TLS_Dynamic:
|
||||||
|
Out << "thread_local ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (D->isModulePrivate())
|
||||||
|
Out << "__module_private__ ";
|
||||||
|
}
|
||||||
|
|
||||||
QualType T = D->getType();
|
QualType T = D->getType();
|
||||||
if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
|
if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
|
||||||
|
|
|
@ -999,7 +999,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
|
||||||
// Check if this is a thread-local variable.
|
// Check if this is a thread-local variable.
|
||||||
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
|
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
|
||||||
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
|
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
|
||||||
if (Var->isThreadSpecified())
|
if (Var->getTLSKind())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D,
|
||||||
if (Linkage != llvm::GlobalValue::InternalLinkage)
|
if (Linkage != llvm::GlobalValue::InternalLinkage)
|
||||||
GV->setVisibility(CurFn->getVisibility());
|
GV->setVisibility(CurFn->getVisibility());
|
||||||
|
|
||||||
if (D.isThreadSpecified())
|
if (D.getTLSKind())
|
||||||
CGM.setTLSMode(GV, D);
|
CGM.setTLSMode(GV, D);
|
||||||
|
|
||||||
return GV;
|
return GV;
|
||||||
|
|
|
@ -39,7 +39,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||||
CodeGenModule &CGM = CGF.CGM;
|
CodeGenModule &CGM = CGF.CGM;
|
||||||
if (lv.isObjCStrong())
|
if (lv.isObjCStrong())
|
||||||
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
|
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
|
||||||
DeclPtr, D.isThreadSpecified());
|
DeclPtr, D.getTLSKind());
|
||||||
else if (lv.isObjCWeak())
|
else if (lv.isObjCWeak())
|
||||||
CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
|
CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init),
|
||||||
DeclPtr);
|
DeclPtr);
|
||||||
|
@ -218,6 +218,9 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
|
||||||
"this initialization requires a guard variable, which "
|
"this initialization requires a guard variable, which "
|
||||||
"the kernel does not support");
|
"the kernel does not support");
|
||||||
|
|
||||||
|
if (D.getTLSKind())
|
||||||
|
CGM.ErrorUnsupported(D.getInit(), "dynamic TLS initialization");
|
||||||
|
|
||||||
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
|
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +257,9 @@ void
|
||||||
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
|
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
|
||||||
llvm::GlobalVariable *Addr,
|
llvm::GlobalVariable *Addr,
|
||||||
bool PerformInit) {
|
bool PerformInit) {
|
||||||
|
if (D->getTLSKind())
|
||||||
|
ErrorUnsupported(D->getInit(), "dynamic TLS initialization");
|
||||||
|
|
||||||
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
|
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
|
||||||
|
|
||||||
// Create a variable initialization function.
|
// Create a variable initialization function.
|
||||||
|
|
|
@ -1667,7 +1667,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
|
||||||
if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
|
if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
|
||||||
if (VD->hasGlobalStorage()) {
|
if (VD->hasGlobalStorage()) {
|
||||||
LV.setGlobalObjCRef(true);
|
LV.setGlobalObjCRef(true);
|
||||||
LV.setThreadLocalRef(VD->isThreadSpecified());
|
LV.setThreadLocalRef(VD->getTLSKind() != VarDecl::TLS_None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LV.setObjCArray(E->getType()->isArrayType());
|
LV.setObjCArray(E->getType()->isArrayType());
|
||||||
|
|
|
@ -333,7 +333,7 @@ static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(
|
||||||
|
|
||||||
void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
|
void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV,
|
||||||
const VarDecl &D) const {
|
const VarDecl &D) const {
|
||||||
assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!");
|
assert(D.getTLSKind() && "setting TLS mode on non-TLS var!");
|
||||||
|
|
||||||
llvm::GlobalVariable::ThreadLocalMode TLM;
|
llvm::GlobalVariable::ThreadLocalMode TLM;
|
||||||
TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
|
TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel());
|
||||||
|
@ -1485,7 +1485,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
|
||||||
GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
|
GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (D->isThreadSpecified())
|
if (D->getTLSKind())
|
||||||
setTLSMode(GV, *D);
|
setTLSMode(GV, *D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1915,7 +1915,7 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
|
||||||
((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
|
((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) ||
|
||||||
D->getAttr<CommonAttr>()) &&
|
D->getAttr<CommonAttr>()) &&
|
||||||
!D->hasExternalStorage() && !D->getInit() &&
|
!D->hasExternalStorage() && !D->getInit() &&
|
||||||
!D->getAttr<SectionAttr>() && !D->isThreadSpecified() &&
|
!D->getAttr<SectionAttr>() && !D->getTLSKind() &&
|
||||||
!D->getAttr<WeakImportAttr>()) {
|
!D->getAttr<WeakImportAttr>()) {
|
||||||
// Thread local vars aren't considered common linkage.
|
// Thread local vars aren't considered common linkage.
|
||||||
return llvm::GlobalVariable::CommonLinkage;
|
return llvm::GlobalVariable::CommonLinkage;
|
||||||
|
|
|
@ -2953,12 +2953,22 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
|
||||||
return New->setInvalidDecl();
|
return New->setInvalidDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (New->isThreadSpecified() && !Old->isThreadSpecified()) {
|
if (New->getTLSKind() != Old->getTLSKind()) {
|
||||||
Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
|
if (!Old->getTLSKind()) {
|
||||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
|
||||||
} else if (!New->isThreadSpecified() && Old->isThreadSpecified()) {
|
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||||
Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName();
|
} else if (!New->getTLSKind()) {
|
||||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName();
|
||||||
|
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||||
|
} else {
|
||||||
|
// Do not allow redeclaration to change the variable between requiring
|
||||||
|
// static and dynamic initialization.
|
||||||
|
// FIXME: GCC allows this, but uses the TLS keyword on the first
|
||||||
|
// declaration to determine the kind. Do we need to be compatible here?
|
||||||
|
Diag(New->getLocation(), diag::err_thread_thread_different_kind)
|
||||||
|
<< New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic);
|
||||||
|
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++ doesn't have tentative definitions, so go right ahead and check here.
|
// C++ doesn't have tentative definitions, so go right ahead and check here.
|
||||||
|
@ -4577,7 +4587,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
|
||||||
if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
|
if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
|
||||||
// Thread-local variables cannot have lifetime.
|
// Thread-local variables cannot have lifetime.
|
||||||
if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
|
if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
|
||||||
var->isThreadSpecified()) {
|
var->getTLSKind()) {
|
||||||
Diag(var->getLocation(), diag::err_arc_thread_ownership)
|
Diag(var->getLocation(), diag::err_arc_thread_ownership)
|
||||||
<< var->getType();
|
<< var->getType();
|
||||||
return true;
|
return true;
|
||||||
|
@ -4851,9 +4861,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
|
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
|
||||||
diag::err_thread_unsupported);
|
diag::err_thread_unsupported);
|
||||||
else
|
else
|
||||||
// FIXME: Track which thread specifier was used; they have different
|
NewVD->setTLSKind(TSCS == DeclSpec::TSCS_thread_local
|
||||||
// semantics.
|
? VarDecl::TLS_Dynamic
|
||||||
NewVD->setThreadSpecified(true);
|
: VarDecl::TLS_Static);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C99 6.7.4p3
|
// C99 6.7.4p3
|
||||||
|
|
|
@ -284,7 +284,7 @@ static bool mayBeSharedVariable(const Decl *D) {
|
||||||
if (isa<FieldDecl>(D))
|
if (isa<FieldDecl>(D))
|
||||||
return true;
|
return true;
|
||||||
if (const VarDecl *vd = dyn_cast<VarDecl>(D))
|
if (const VarDecl *vd = dyn_cast<VarDecl>(D))
|
||||||
return (vd->hasGlobalStorage() && !(vd->isThreadSpecified()));
|
return vd->hasGlobalStorage() && !vd->getTLSKind();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1656,7 +1656,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) {
|
if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) {
|
||||||
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
|
||||||
<< Attr.getName() << ExpectedTLSVar;
|
<< Attr.getName() << ExpectedTLSVar;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -165,8 +165,8 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if threadspecified is set.
|
// Check if this is a TLS variable.
|
||||||
if (VD->isThreadSpecified()) {
|
if (VD->getTLSKind()) {
|
||||||
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
|
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
|
||||||
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
|
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -3842,8 +3842,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A template argument must have static storage duration.
|
// A template argument must have static storage duration.
|
||||||
// FIXME: Ensure this works for thread_local as well as __thread.
|
if (Var->getTLSKind()) {
|
||||||
if (Var->isThreadSpecified()) {
|
|
||||||
S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local)
|
S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local)
|
||||||
<< Arg->getSourceRange();
|
<< Arg->getSourceRange();
|
||||||
S.Diag(Var->getLocation(), diag::note_template_arg_refers_here);
|
S.Diag(Var->getLocation(), diag::note_template_arg_refers_here);
|
||||||
|
|
|
@ -339,7 +339,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
||||||
D->getLocation(), D->getIdentifier(),
|
D->getLocation(), D->getIdentifier(),
|
||||||
DI->getType(), DI,
|
DI->getType(), DI,
|
||||||
D->getStorageClass());
|
D->getStorageClass());
|
||||||
Var->setThreadSpecified(D->isThreadSpecified());
|
Var->setTLSKind(D->getTLSKind());
|
||||||
Var->setInitStyle(D->getInitStyle());
|
Var->setInitStyle(D->getInitStyle());
|
||||||
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
|
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
|
||||||
Var->setConstexpr(D->isConstexpr());
|
Var->setConstexpr(D->isConstexpr());
|
||||||
|
|
|
@ -895,7 +895,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
|
||||||
VisitDeclaratorDecl(VD);
|
VisitDeclaratorDecl(VD);
|
||||||
|
|
||||||
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
|
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
|
||||||
VD->VarDeclBits.ThreadSpecified = Record[Idx++];
|
VD->VarDeclBits.TLSKind = Record[Idx++];
|
||||||
VD->VarDeclBits.InitStyle = Record[Idx++];
|
VD->VarDeclBits.InitStyle = Record[Idx++];
|
||||||
VD->VarDeclBits.ExceptionVar = Record[Idx++];
|
VD->VarDeclBits.ExceptionVar = Record[Idx++];
|
||||||
VD->VarDeclBits.NRVOVariable = Record[Idx++];
|
VD->VarDeclBits.NRVOVariable = Record[Idx++];
|
||||||
|
|
|
@ -677,7 +677,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
||||||
VisitRedeclarable(D);
|
VisitRedeclarable(D);
|
||||||
VisitDeclaratorDecl(D);
|
VisitDeclaratorDecl(D);
|
||||||
Record.push_back(D->getStorageClass());
|
Record.push_back(D->getStorageClass());
|
||||||
Record.push_back(D->isThreadSpecified());
|
Record.push_back(D->getTLSKind());
|
||||||
Record.push_back(D->getInitStyle());
|
Record.push_back(D->getInitStyle());
|
||||||
Record.push_back(D->isExceptionVariable());
|
Record.push_back(D->isExceptionVariable());
|
||||||
Record.push_back(D->isNRVOVariable());
|
Record.push_back(D->isNRVOVariable());
|
||||||
|
@ -766,7 +766,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
||||||
|
|
||||||
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
|
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
|
||||||
// just us assuming it.
|
// just us assuming it.
|
||||||
assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread");
|
assert(!D->getTLSKind() && "PARM_VAR_DECL can't use TLS");
|
||||||
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
|
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
|
||||||
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
|
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
|
||||||
assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl");
|
assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl");
|
||||||
|
@ -1515,7 +1515,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
||||||
// VarDecl
|
// VarDecl
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
|
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
|
Abv->Add(BitCodeAbbrevOp(0)); // getTLSKind
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
|
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
|
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
|
Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable
|
||||||
|
@ -1594,7 +1594,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
|
||||||
// VarDecl
|
// VarDecl
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTLSKind
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
|
||||||
|
|
|
@ -4,16 +4,20 @@ namespace std {
|
||||||
typedef decltype(nullptr) nullptr_t;
|
typedef decltype(nullptr) nullptr_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int *ip> struct IP { // expected-note 4 {{template parameter is declared here}}
|
template<int *ip> struct IP { // expected-note 5 {{template parameter is declared here}}
|
||||||
IP<ip> *ip2;
|
IP<ip> *ip2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<int &ip> struct IR {};
|
||||||
|
|
||||||
constexpr std::nullptr_t get_nullptr() { return nullptr; }
|
constexpr std::nullptr_t get_nullptr() { return nullptr; }
|
||||||
|
|
||||||
constexpr std::nullptr_t np = nullptr;
|
constexpr std::nullptr_t np = nullptr;
|
||||||
|
|
||||||
std::nullptr_t nonconst_np; // expected-note{{declared here}}
|
std::nullptr_t nonconst_np; // expected-note{{declared here}}
|
||||||
|
|
||||||
|
thread_local int tl; // expected-note {{refers here}}
|
||||||
|
|
||||||
IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
|
IP<0> ip0; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
|
||||||
IP<(0)> ip1; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
|
IP<(0)> ip1; // expected-error{{null non-type template argument must be cast to template parameter type 'int *'}}
|
||||||
IP<nullptr> ip2;
|
IP<nullptr> ip2;
|
||||||
|
@ -23,6 +27,9 @@ IP<np> ip5;
|
||||||
IP<nonconst_np> ip5; // expected-error{{non-type template argument of type 'std::nullptr_t' (aka 'nullptr_t') is not a constant expression}} \
|
IP<nonconst_np> ip5; // expected-error{{non-type template argument of type 'std::nullptr_t' (aka 'nullptr_t') is not a constant expression}} \
|
||||||
// expected-note{{read of non-constexpr variable 'nonconst_np' is not allowed in a constant expression}}
|
// expected-note{{read of non-constexpr variable 'nonconst_np' is not allowed in a constant expression}}
|
||||||
IP<(float*)0> ip6; // expected-error{{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}}
|
IP<(float*)0> ip6; // expected-error{{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}}
|
||||||
|
IP<&tl> ip7; // expected-error{{non-type template argument of type 'int *' is not a constant expression}}
|
||||||
|
|
||||||
|
IR<tl> ir1; // expected-error{{non-type template argument refers to thread-local object}}
|
||||||
|
|
||||||
struct X { };
|
struct X { };
|
||||||
template<int X::*pm> struct PM { // expected-note 2 {{template parameter is declared here}}
|
template<int X::*pm> struct PM { // expected-note 2 {{template parameter is declared here}}
|
||||||
|
|
|
@ -139,7 +139,7 @@ extern int TestVarDeclSC;
|
||||||
// CHECK: VarDecl{{.*}} TestVarDeclSC 'int' extern
|
// CHECK: VarDecl{{.*}} TestVarDeclSC 'int' extern
|
||||||
|
|
||||||
__thread int TestVarDeclThread;
|
__thread int TestVarDeclThread;
|
||||||
// CHECK: VarDecl{{.*}} TestVarDeclThread 'int' __thread
|
// CHECK: VarDecl{{.*}} TestVarDeclThread 'int' tls{{$}}
|
||||||
|
|
||||||
__module_private__ int TestVarDeclPrivate;
|
__module_private__ int TestVarDeclPrivate;
|
||||||
// CHECK: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
|
// CHECK: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
|
||||||
|
|
|
@ -92,6 +92,9 @@ class TestCXXRecordDeclPack : public T... {
|
||||||
// CHECK-NEXT: public 'T'...
|
// CHECK-NEXT: public 'T'...
|
||||||
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
|
// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
|
||||||
|
|
||||||
|
thread_local int TestThreadLocalInt;
|
||||||
|
// CHECK: TestThreadLocalInt {{.*}} tls_dynamic
|
||||||
|
|
||||||
__module_private__ class TestCXXRecordDeclPrivate;
|
__module_private__ class TestCXXRecordDeclPrivate;
|
||||||
// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPrivate __module_private__
|
// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPrivate __module_private__
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
|
||||||
|
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
|
||||||
|
|
||||||
|
#ifndef HEADER_INCLUDED
|
||||||
|
|
||||||
|
#define HEADER_INCLUDED
|
||||||
|
extern thread_local int a;
|
||||||
|
extern _Thread_local int b;
|
||||||
|
extern int c;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
_Thread_local int a; // expected-error {{thread-local declaration of 'a' with static initialization follows declaration with dynamic initialization}}
|
||||||
|
// expected-note@7 {{previous declaration is here}}
|
||||||
|
thread_local int b; // expected-error {{thread-local declaration of 'b' with dynamic initialization follows declaration with static initialization}}
|
||||||
|
// expected-note@8 {{previous declaration is here}}
|
||||||
|
thread_local int c; // expected-error {{thread-local declaration of 'c' follows non-thread-local declaration}}
|
||||||
|
// expected-note@9 {{previous declaration is here}}
|
||||||
|
|
||||||
|
#endif
|
|
@ -59,11 +59,18 @@ int f(__thread int t7) { // expected-error {{' is only allowed on variable decla
|
||||||
}
|
}
|
||||||
|
|
||||||
__thread typedef int t14; // expected-error-re {{cannot combine with previous '(__thread|_Thread_local|thread_local)' declaration specifier}}
|
__thread typedef int t14; // expected-error-re {{cannot combine with previous '(__thread|_Thread_local|thread_local)' declaration specifier}}
|
||||||
__thread int t15; // expected-note {{previous definition is here}}
|
__thread int t15; // expected-note {{previous declaration is here}}
|
||||||
extern int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
|
extern int t15; // expected-error {{non-thread-local declaration of 't15' follows thread-local declaration}}
|
||||||
extern int t16; // expected-note {{previous definition is here}}
|
extern int t16; // expected-note {{previous declaration is here}}
|
||||||
__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
|
__thread int t16; // expected-error {{thread-local declaration of 't16' follows non-thread-local declaration}}
|
||||||
|
|
||||||
|
#ifdef CXX11
|
||||||
|
extern thread_local int t17; // expected-note {{previous declaration is here}}
|
||||||
|
_Thread_local int t17; // expected-error {{thread-local declaration of 't17' with static initialization follows declaration with dynamic initialization}}
|
||||||
|
extern _Thread_local int t18; // expected-note {{previous declaration is here}}
|
||||||
|
thread_local int t18; // expected-error {{thread-local declaration of 't18' with dynamic initialization follows declaration with static initialization}}
|
||||||
|
#endif
|
||||||
|
|
||||||
// PR13720
|
// PR13720
|
||||||
__thread int thread_int;
|
__thread int thread_int;
|
||||||
int *thread_int_ptr = &thread_int;
|
int *thread_int_ptr = &thread_int;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче