mirror of https://github.com/microsoft/clang.git
CodeGen: Fix linkage of reference temporaries
Summary: A reference temporary should inherit the linkage of the variable it initializes. Otherwise, we may hit cases where a reference temporary wouldn't have the same value in all translation units. Reviewers: rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D3515 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@207451 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ec47c9130c
commit
f5563f5736
|
@ -59,10 +59,9 @@ enum LanguageLinkage {
|
||||||
/// This is relevant to CodeGen and AST file reading.
|
/// This is relevant to CodeGen and AST file reading.
|
||||||
enum GVALinkage {
|
enum GVALinkage {
|
||||||
GVA_Internal,
|
GVA_Internal,
|
||||||
GVA_C99Inline,
|
GVA_AvailableExternally,
|
||||||
GVA_CXXInline,
|
GVA_DiscardableODR,
|
||||||
GVA_StrongExternal,
|
GVA_StrongExternal,
|
||||||
GVA_TemplateInstantiation,
|
|
||||||
GVA_StrongODR
|
GVA_StrongODR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7767,8 +7767,10 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
|
||||||
return GVA_StrongODR;
|
return GVA_StrongODR;
|
||||||
|
|
||||||
case TSK_ExplicitInstantiationDeclaration:
|
case TSK_ExplicitInstantiationDeclaration:
|
||||||
|
return GVA_AvailableExternally;
|
||||||
|
|
||||||
case TSK_ImplicitInstantiation:
|
case TSK_ImplicitInstantiation:
|
||||||
External = GVA_TemplateInstantiation;
|
External = GVA_DiscardableODR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7783,7 +7785,7 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
|
||||||
return External;
|
return External;
|
||||||
|
|
||||||
// C99 inline semantics, where the symbol is not externally visible.
|
// C99 inline semantics, where the symbol is not externally visible.
|
||||||
return GVA_C99Inline;
|
return GVA_AvailableExternally;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++0x [temp.explicit]p9:
|
// C++0x [temp.explicit]p9:
|
||||||
|
@ -7794,7 +7796,7 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
|
||||||
// generated in the translation unit. -- end note ]
|
// generated in the translation unit. -- end note ]
|
||||||
if (FD->getTemplateSpecializationKind()
|
if (FD->getTemplateSpecializationKind()
|
||||||
== TSK_ExplicitInstantiationDeclaration)
|
== TSK_ExplicitInstantiationDeclaration)
|
||||||
return GVA_C99Inline;
|
return GVA_AvailableExternally;
|
||||||
|
|
||||||
// Functions specified with extern and inline in -fms-compatibility mode
|
// Functions specified with extern and inline in -fms-compatibility mode
|
||||||
// forcibly get emitted. While the body of the function cannot be later
|
// forcibly get emitted. While the body of the function cannot be later
|
||||||
|
@ -7802,27 +7804,53 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
|
||||||
if (FD->getMostRecentDecl()->isMSExternInline())
|
if (FD->getMostRecentDecl()->isMSExternInline())
|
||||||
return GVA_StrongODR;
|
return GVA_StrongODR;
|
||||||
|
|
||||||
return GVA_CXXInline;
|
return GVA_DiscardableODR;
|
||||||
}
|
}
|
||||||
|
|
||||||
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
|
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
|
||||||
if (!VD->isExternallyVisible())
|
if (!VD->isExternallyVisible())
|
||||||
return GVA_Internal;
|
return GVA_Internal;
|
||||||
|
|
||||||
|
if (VD->isStaticLocal()) {
|
||||||
|
GVALinkage StaticLocalLinkage = GVA_DiscardableODR;
|
||||||
|
const DeclContext *LexicalContext = VD->getParentFunctionOrMethod();
|
||||||
|
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
|
||||||
|
LexicalContext = LexicalContext->getLexicalParent();
|
||||||
|
|
||||||
|
// Let the static local variable inherit it's linkage from the nearest
|
||||||
|
// enclosing function.
|
||||||
|
if (LexicalContext)
|
||||||
|
StaticLocalLinkage =
|
||||||
|
GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
|
||||||
|
|
||||||
|
// GVA_StrongODR function linkage is stronger than what we need,
|
||||||
|
// downgrade to GVA_DiscardableODR.
|
||||||
|
// This allows us to discard the variable if we never end up needing it.
|
||||||
|
return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR
|
||||||
|
: StaticLocalLinkage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Darwin, the backing variable for a C++11 thread_local variable always
|
||||||
|
// has internal linkage; all accesses should just be calls to the
|
||||||
|
// Itanium-specified entry point, which has the normal linkage of the
|
||||||
|
// variable.
|
||||||
|
if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
|
||||||
|
getTargetInfo().getTriple().isMacOSX())
|
||||||
|
return GVA_Internal;
|
||||||
|
|
||||||
switch (VD->getTemplateSpecializationKind()) {
|
switch (VD->getTemplateSpecializationKind()) {
|
||||||
case TSK_Undeclared:
|
case TSK_Undeclared:
|
||||||
case TSK_ExplicitSpecialization:
|
case TSK_ExplicitSpecialization:
|
||||||
return GVA_StrongExternal;
|
return GVA_StrongExternal;
|
||||||
|
|
||||||
case TSK_ExplicitInstantiationDeclaration:
|
|
||||||
llvm_unreachable("Variable should not be instantiated");
|
|
||||||
// Fall through to treat this like any other instantiation.
|
|
||||||
|
|
||||||
case TSK_ExplicitInstantiationDefinition:
|
case TSK_ExplicitInstantiationDefinition:
|
||||||
return GVA_StrongODR;
|
return GVA_StrongODR;
|
||||||
|
|
||||||
|
case TSK_ExplicitInstantiationDeclaration:
|
||||||
|
return GVA_AvailableExternally;
|
||||||
|
|
||||||
case TSK_ImplicitInstantiation:
|
case TSK_ImplicitInstantiation:
|
||||||
return GVA_TemplateInstantiation;
|
return GVA_DiscardableODR;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("Invalid Linkage!");
|
llvm_unreachable("Invalid Linkage!");
|
||||||
|
@ -7878,8 +7906,8 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||||
// static, static inline, always_inline, and extern inline functions can
|
// static, static inline, always_inline, and extern inline functions can
|
||||||
// always be deferred. Normal inline functions can be deferred in C99/C++.
|
// always be deferred. Normal inline functions can be deferred in C99/C++.
|
||||||
// Implicit template instantiations can also be deferred in C++.
|
// Implicit template instantiations can also be deferred in C++.
|
||||||
if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
|
if (Linkage == GVA_Internal || Linkage == GVA_AvailableExternally ||
|
||||||
Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
|
Linkage == GVA_DiscardableODR)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7892,7 +7920,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||||
|
|
||||||
// Variables that can be needed in other TUs are required.
|
// Variables that can be needed in other TUs are required.
|
||||||
GVALinkage L = GetGVALinkageForVariable(VD);
|
GVALinkage L = GetGVALinkageForVariable(VD);
|
||||||
if (L != GVA_Internal && L != GVA_TemplateInstantiation)
|
if (L != GVA_Internal && L != GVA_DiscardableODR)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Variables that have destruction with side-effects are required.
|
// Variables that have destruction with side-effects are required.
|
||||||
|
|
|
@ -126,17 +126,11 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
||||||
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
|
void CodeGenFunction::EmitVarDecl(const VarDecl &D) {
|
||||||
if (D.isStaticLocal()) {
|
if (D.isStaticLocal()) {
|
||||||
llvm::GlobalValue::LinkageTypes Linkage =
|
llvm::GlobalValue::LinkageTypes Linkage =
|
||||||
llvm::GlobalValue::InternalLinkage;
|
CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false);
|
||||||
|
|
||||||
// If the variable is externally visible, it must have weak linkage so it
|
|
||||||
// can be uniqued.
|
|
||||||
if (D.isExternallyVisible()) {
|
|
||||||
Linkage = llvm::GlobalValue::LinkOnceODRLinkage;
|
|
||||||
|
|
||||||
// FIXME: We need to force the emission/use of a guard variable for
|
// FIXME: We need to force the emission/use of a guard variable for
|
||||||
// some variables even if we can constant-evaluate them because
|
// some variables even if we can constant-evaluate them because
|
||||||
// we can't guarantee every translation unit will constant-evaluate them.
|
// we can't guarantee every translation unit will constant-evaluate them.
|
||||||
}
|
|
||||||
|
|
||||||
return EmitStaticVarDecl(D, Linkage);
|
return EmitStaticVarDecl(D, Linkage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,8 +417,8 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
|
||||||
// Use guarded initialization if the global variable is weak. This
|
// Use guarded initialization if the global variable is weak. This
|
||||||
// occurs for, e.g., instantiated static data members and
|
// occurs for, e.g., instantiated static data members and
|
||||||
// definitions explicitly marked weak.
|
// definitions explicitly marked weak.
|
||||||
if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage ||
|
if (llvm::GlobalVariable::isWeakLinkage(Addr->getLinkage()) ||
|
||||||
Addr->getLinkage() == llvm::GlobalValue::WeakAnyLinkage) {
|
llvm::GlobalVariable::isLinkOnceLinkage(Addr->getLinkage())) {
|
||||||
EmitCXXGuardedInit(*D, Addr, PerformInit);
|
EmitCXXGuardedInit(*D, Addr, PerformInit);
|
||||||
} else {
|
} else {
|
||||||
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
|
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
|
||||||
|
|
|
@ -568,55 +568,13 @@ CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
|
||||||
|
|
||||||
GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
|
GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
|
||||||
|
|
||||||
if (Linkage == GVA_Internal)
|
bool UseThunkForDtorVariant =
|
||||||
return llvm::Function::InternalLinkage;
|
isa<CXXDestructorDecl>(D) &&
|
||||||
|
|
||||||
if (D->hasAttr<DLLExportAttr>())
|
|
||||||
return llvm::Function::ExternalLinkage;
|
|
||||||
|
|
||||||
if (D->hasAttr<WeakAttr>())
|
|
||||||
return llvm::Function::WeakAnyLinkage;
|
|
||||||
|
|
||||||
// In C99 mode, 'inline' functions are guaranteed to have a strong
|
|
||||||
// definition somewhere else, so we can use available_externally linkage.
|
|
||||||
if (Linkage == GVA_C99Inline)
|
|
||||||
return llvm::Function::AvailableExternallyLinkage;
|
|
||||||
|
|
||||||
// Note that Apple's kernel linker doesn't support symbol
|
|
||||||
// coalescing, so we need to avoid linkonce and weak linkages there.
|
|
||||||
// Normally, this means we just map to internal, but for explicit
|
|
||||||
// instantiations we'll map to external.
|
|
||||||
|
|
||||||
// In C++, the compiler has to emit a definition in every translation unit
|
|
||||||
// that references the function. We should use linkonce_odr because
|
|
||||||
// a) if all references in this translation unit are optimized away, we
|
|
||||||
// don't need to codegen it. b) if the function persists, it needs to be
|
|
||||||
// merged with other definitions. c) C++ has the ODR, so we know the
|
|
||||||
// definition is dependable.
|
|
||||||
if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
|
|
||||||
return !Context.getLangOpts().AppleKext
|
|
||||||
? llvm::Function::LinkOnceODRLinkage
|
|
||||||
: llvm::Function::InternalLinkage;
|
|
||||||
|
|
||||||
// An explicit instantiation of a template has weak linkage, since
|
|
||||||
// explicit instantiations can occur in multiple translation units
|
|
||||||
// and must all be equivalent. However, we are not allowed to
|
|
||||||
// throw away these explicit instantiations.
|
|
||||||
if (Linkage == GVA_StrongODR)
|
|
||||||
return !Context.getLangOpts().AppleKext
|
|
||||||
? llvm::Function::WeakODRLinkage
|
|
||||||
: llvm::Function::ExternalLinkage;
|
|
||||||
|
|
||||||
// Destructor variants in the Microsoft C++ ABI are always linkonce_odr thunks
|
|
||||||
// emitted on an as-needed basis.
|
|
||||||
if (isa<CXXDestructorDecl>(D) &&
|
|
||||||
getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
|
getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
|
||||||
GD.getDtorType()))
|
GD.getDtorType());
|
||||||
return llvm::Function::LinkOnceODRLinkage;
|
|
||||||
|
|
||||||
// Otherwise, we have strong external linkage.
|
return getLLVMLinkageforDeclarator(D, Linkage, /*isConstantVariable=*/false,
|
||||||
assert(Linkage == GVA_StrongExternal);
|
UseThunkForDtorVariant);
|
||||||
return llvm::Function::ExternalLinkage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1904,7 +1862,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
|
||||||
|
|
||||||
// Set the llvm linkage type as appropriate.
|
// Set the llvm linkage type as appropriate.
|
||||||
llvm::GlobalValue::LinkageTypes Linkage =
|
llvm::GlobalValue::LinkageTypes Linkage =
|
||||||
GetLLVMLinkageVarDefinition(D, GV->isConstant());
|
getLLVMLinkageVarDefinition(D, GV->isConstant());
|
||||||
GV->setLinkage(Linkage);
|
GV->setLinkage(Linkage);
|
||||||
if (D->hasAttr<DLLImportAttr>())
|
if (D->hasAttr<DLLImportAttr>())
|
||||||
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
|
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
|
||||||
|
@ -1967,48 +1925,93 @@ static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::GlobalValue::LinkageTypes
|
llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageforDeclarator(
|
||||||
CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
|
const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable,
|
||||||
GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
|
bool UseThunkForDtorVariant) {
|
||||||
if (Linkage == GVA_Internal)
|
if (Linkage == GVA_Internal)
|
||||||
return llvm::Function::InternalLinkage;
|
return llvm::Function::InternalLinkage;
|
||||||
else if (D->hasAttr<DLLImportAttr>())
|
|
||||||
return llvm::Function::ExternalLinkage;
|
if (D->hasAttr<WeakAttr>()) {
|
||||||
else if (D->hasAttr<DLLExportAttr>())
|
if (IsConstantVariable)
|
||||||
return llvm::Function::ExternalLinkage;
|
return llvm::GlobalVariable::WeakODRLinkage;
|
||||||
else if (D->hasAttr<SelectAnyAttr>()) {
|
else
|
||||||
|
return llvm::GlobalVariable::WeakAnyLinkage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are guaranteed to have a strong definition somewhere else,
|
||||||
|
// so we can use available_externally linkage.
|
||||||
|
if (Linkage == GVA_AvailableExternally)
|
||||||
|
return llvm::Function::AvailableExternallyLinkage;
|
||||||
|
|
||||||
|
// LinkOnceODRLinkage is insufficient if the symbol is required to exist in
|
||||||
|
// the symbol table. Promote the linkage to WeakODRLinkage to preserve the
|
||||||
|
// semantics of LinkOnceODRLinkage while providing visibility in the symbol
|
||||||
|
// table.
|
||||||
|
llvm::GlobalValue::LinkageTypes OnceLinkage =
|
||||||
|
llvm::GlobalValue::LinkOnceODRLinkage;
|
||||||
|
if (D->hasAttr<DLLExportAttr>() || D->hasAttr<DLLImportAttr>())
|
||||||
|
OnceLinkage = llvm::GlobalVariable::WeakODRLinkage;
|
||||||
|
|
||||||
|
// Note that Apple's kernel linker doesn't support symbol
|
||||||
|
// coalescing, so we need to avoid linkonce and weak linkages there.
|
||||||
|
// Normally, this means we just map to internal, but for explicit
|
||||||
|
// instantiations we'll map to external.
|
||||||
|
|
||||||
|
// In C++, the compiler has to emit a definition in every translation unit
|
||||||
|
// that references the function. We should use linkonce_odr because
|
||||||
|
// a) if all references in this translation unit are optimized away, we
|
||||||
|
// don't need to codegen it. b) if the function persists, it needs to be
|
||||||
|
// merged with other definitions. c) C++ has the ODR, so we know the
|
||||||
|
// definition is dependable.
|
||||||
|
if (Linkage == GVA_DiscardableODR)
|
||||||
|
return !Context.getLangOpts().AppleKext ? OnceLinkage
|
||||||
|
: llvm::Function::InternalLinkage;
|
||||||
|
|
||||||
|
// An explicit instantiation of a template has weak linkage, since
|
||||||
|
// explicit instantiations can occur in multiple translation units
|
||||||
|
// and must all be equivalent. However, we are not allowed to
|
||||||
|
// throw away these explicit instantiations.
|
||||||
|
if (Linkage == GVA_StrongODR)
|
||||||
|
return !Context.getLangOpts().AppleKext ? llvm::Function::WeakODRLinkage
|
||||||
|
: llvm::Function::ExternalLinkage;
|
||||||
|
|
||||||
|
// Destructor variants in the Microsoft C++ ABI are always linkonce_odr thunks
|
||||||
|
// emitted on an as-needed basis.
|
||||||
|
if (UseThunkForDtorVariant)
|
||||||
|
return OnceLinkage;
|
||||||
|
|
||||||
|
// If required by the ABI, give definitions of static data members with inline
|
||||||
|
// initializers at least linkonce_odr linkage.
|
||||||
|
if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
|
||||||
|
isa<VarDecl>(D) &&
|
||||||
|
isVarDeclInlineInitializedStaticDataMember(cast<VarDecl>(D)))
|
||||||
|
return OnceLinkage;
|
||||||
|
|
||||||
|
// C++ doesn't have tentative definitions and thus cannot have common
|
||||||
|
// linkage.
|
||||||
|
if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
|
||||||
|
!isVarDeclStrongDefinition(cast<VarDecl>(D), CodeGenOpts.NoCommon))
|
||||||
|
return llvm::GlobalVariable::CommonLinkage;
|
||||||
|
|
||||||
// selectany symbols are externally visible, so use weak instead of
|
// selectany symbols are externally visible, so use weak instead of
|
||||||
// linkonce. MSVC optimizes away references to const selectany globals, so
|
// linkonce. MSVC optimizes away references to const selectany globals, so
|
||||||
// all definitions should be the same and ODR linkage should be used.
|
// all definitions should be the same and ODR linkage should be used.
|
||||||
// http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
|
// http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
|
||||||
|
if (D->hasAttr<SelectAnyAttr>())
|
||||||
return llvm::GlobalVariable::WeakODRLinkage;
|
return llvm::GlobalVariable::WeakODRLinkage;
|
||||||
} else if (D->hasAttr<WeakAttr>()) {
|
|
||||||
if (isConstant)
|
|
||||||
return llvm::GlobalVariable::WeakODRLinkage;
|
|
||||||
else
|
|
||||||
return llvm::GlobalVariable::WeakAnyLinkage;
|
|
||||||
} else if (Linkage == GVA_TemplateInstantiation || Linkage == GVA_StrongODR)
|
|
||||||
return llvm::GlobalVariable::WeakODRLinkage;
|
|
||||||
else if (D->getTLSKind() == VarDecl::TLS_Dynamic &&
|
|
||||||
getTarget().getTriple().isMacOSX())
|
|
||||||
// On Darwin, the backing variable for a C++11 thread_local variable always
|
|
||||||
// has internal linkage; all accesses should just be calls to the
|
|
||||||
// Itanium-specified entry point, which has the normal linkage of the
|
|
||||||
// variable.
|
|
||||||
return llvm::GlobalValue::InternalLinkage;
|
|
||||||
else if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
|
|
||||||
isVarDeclInlineInitializedStaticDataMember(D))
|
|
||||||
// If required by the ABI, give definitions of static data members with inline
|
|
||||||
// initializers linkonce_odr linkage.
|
|
||||||
return llvm::GlobalVariable::LinkOnceODRLinkage;
|
|
||||||
// C++ doesn't have tentative definitions and thus cannot have common linkage.
|
|
||||||
else if (!getLangOpts().CPlusPlus &&
|
|
||||||
!isVarDeclStrongDefinition(D, CodeGenOpts.NoCommon))
|
|
||||||
return llvm::GlobalVariable::CommonLinkage;
|
|
||||||
|
|
||||||
|
// Otherwise, we have strong external linkage.
|
||||||
|
assert(Linkage == GVA_StrongExternal);
|
||||||
return llvm::GlobalVariable::ExternalLinkage;
|
return llvm::GlobalVariable::ExternalLinkage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageVarDefinition(
|
||||||
|
const VarDecl *VD, bool IsConstant) {
|
||||||
|
GVALinkage Linkage = getContext().GetGVALinkageForVariable(VD);
|
||||||
|
return getLLVMLinkageforDeclarator(VD, Linkage, IsConstant,
|
||||||
|
/*UseThunkForDtorVariant=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace the uses of a function that was declared with a non-proto type.
|
/// Replace the uses of a function that was declared with a non-proto type.
|
||||||
/// We want to silently drop extra arguments from call sites
|
/// We want to silently drop extra arguments from call sites
|
||||||
static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
|
static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
|
||||||
|
@ -2860,10 +2863,16 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a global variable for this lifetime-extended temporary.
|
// Create a global variable for this lifetime-extended temporary.
|
||||||
llvm::GlobalVariable *GV =
|
llvm::GlobalValue::LinkageTypes Linkage =
|
||||||
new llvm::GlobalVariable(getModule(), Type, Constant,
|
getLLVMLinkageVarDefinition(VD, Constant);
|
||||||
llvm::GlobalValue::PrivateLinkage,
|
if (Linkage == llvm::GlobalVariable::ExternalLinkage)
|
||||||
InitialValue, Name.c_str());
|
Linkage = llvm::GlobalVariable::PrivateLinkage;
|
||||||
|
unsigned AddrSpace = GetGlobalVarAddressSpace(
|
||||||
|
VD, getContext().getTargetAddressSpace(MaterializedType));
|
||||||
|
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
|
||||||
|
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
|
||||||
|
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
|
||||||
|
AddrSpace);
|
||||||
GV->setAlignment(
|
GV->setAlignment(
|
||||||
getContext().getTypeAlignInChars(MaterializedType).getQuantity());
|
getContext().getTypeAlignInChars(MaterializedType).getQuantity());
|
||||||
if (VD->getTLSKind())
|
if (VD->getTLSKind())
|
||||||
|
|
|
@ -979,10 +979,15 @@ public:
|
||||||
/// the given LLVM type.
|
/// the given LLVM type.
|
||||||
CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
|
CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const;
|
||||||
|
|
||||||
/// GetLLVMLinkageVarDefinition - Returns LLVM linkage for a global
|
/// getLLVMLinkageforDeclarator - Returns LLVM linkage for a declarator.
|
||||||
/// variable.
|
|
||||||
llvm::GlobalValue::LinkageTypes
|
llvm::GlobalValue::LinkageTypes
|
||||||
GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant);
|
getLLVMLinkageforDeclarator(const DeclaratorDecl *D, GVALinkage Linkage,
|
||||||
|
bool IsConstantVariable,
|
||||||
|
bool UseThunkForDtorVariant);
|
||||||
|
|
||||||
|
/// getLLVMLinkageVarDefinition - Returns LLVM linkage for a declarator.
|
||||||
|
llvm::GlobalValue::LinkageTypes
|
||||||
|
getLLVMLinkageVarDefinition(const VarDecl *VD, bool IsConstant);
|
||||||
|
|
||||||
/// Emit all the global annotations.
|
/// Emit all the global annotations.
|
||||||
void EmitGlobalAnnotations();
|
void EmitGlobalAnnotations();
|
||||||
|
|
|
@ -4936,7 +4936,8 @@ static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) {
|
||||||
FD->setLazyBody(1);
|
FD->setLazyBody(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool isC99Inline = (S.Context.GetGVALinkageForFunction(FD) == GVA_C99Inline);
|
bool isC99Inline =
|
||||||
|
S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
FD->setLazyBody(0);
|
FD->setLazyBody(0);
|
||||||
|
|
|
@ -20,8 +20,8 @@ template int X<int>::member2;
|
||||||
|
|
||||||
// For implicit instantiation of
|
// For implicit instantiation of
|
||||||
long& get(bool Cond1, bool Cond2) {
|
long& get(bool Cond1, bool Cond2) {
|
||||||
// CHECK: @_ZN1XIlE7member1E = weak_odr global i64 0
|
// CHECK: @_ZN1XIlE7member1E = linkonce_odr global i64 0
|
||||||
// CHECK: @_ZN1XIlE7member2E = weak_odr global i64 17
|
// CHECK: @_ZN1XIlE7member2E = linkonce_odr global i64 17
|
||||||
// CHECK: @_ZN1XIlE7member3E = external global i64
|
// CHECK: @_ZN1XIlE7member3E = external global i64
|
||||||
return Cond1? X<long>::member1
|
return Cond1? X<long>::member1
|
||||||
: Cond2? X<long>::member2
|
: Cond2? X<long>::member2
|
||||||
|
|
|
@ -393,6 +393,9 @@ namespace UnemittedTemporaryDecl {
|
||||||
// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
|
// CHECK: @_ZZN12LocalVarInit3aggEvE1a = internal constant {{.*}} i32 101
|
||||||
// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102
|
// CHECK: @_ZZN12LocalVarInit4ctorEvE1a = internal constant {{.*}} i32 102
|
||||||
// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103
|
// CHECK: @_ZZN12LocalVarInit8mutable_EvE1a = private unnamed_addr constant {{.*}} i32 103
|
||||||
|
// CHECK: @_ZGRN33ClassTemplateWithStaticDataMember1SIvE1aE = linkonce_odr constant i32 5
|
||||||
|
// CHECK: @_ZN33ClassTemplateWithStaticDataMember3useE = constant i32* @_ZGRN33ClassTemplateWithStaticDataMember1SIvE1aE
|
||||||
|
// CHECK: @_ZGRZN20InlineStaticConstRef3funEvE1i = linkonce_odr constant i32 10
|
||||||
|
|
||||||
// Constant initialization tests go before this point,
|
// Constant initialization tests go before this point,
|
||||||
// dynamic initialization tests go after.
|
// dynamic initialization tests go after.
|
||||||
|
@ -552,3 +555,22 @@ namespace Null {
|
||||||
// CHECK: call {{.*}} @_ZN4Null4nullEv(
|
// CHECK: call {{.*}} @_ZN4Null4nullEv(
|
||||||
int S::*q = null();
|
int S::*q = null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace InlineStaticConstRef {
|
||||||
|
inline const int &fun() {
|
||||||
|
static const int &i = 10;
|
||||||
|
return i;
|
||||||
|
// CHECK: ret i32* @_ZGRZN20InlineStaticConstRef3funEvE1i
|
||||||
|
}
|
||||||
|
const int &use = fun();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ClassTemplateWithStaticDataMember {
|
||||||
|
template <typename T>
|
||||||
|
struct S {
|
||||||
|
static const int &a;
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
const int &S<T>::a = 5;
|
||||||
|
const int &use = S<void>::a;
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,36 @@ namespace ModifyStaticTemporary {
|
||||||
// CHECK: @_ZN21ModifyStaticTemporary1cE = global {{.*}} zeroinitializer
|
// CHECK: @_ZN21ModifyStaticTemporary1cE = global {{.*}} zeroinitializer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: @_ZGRN28VariableTemplateWithConstRef1iIvEE = linkonce_odr constant i32 5, align 4
|
||||||
|
// CHECK: @_ZN28VariableTemplateWithConstRef3useE = constant i32* @_ZGRN28VariableTemplateWithConstRef1iIvEE
|
||||||
|
namespace VariableTemplateWithConstRef {
|
||||||
|
template <typename T>
|
||||||
|
const int &i = 5;
|
||||||
|
const int &use = i<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE = linkonce_odr constant i32 1
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE }
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3 = linkonce_odr constant i32 2
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3 }
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5 = linkonce_odr constant i32 3
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5 }
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7 = linkonce_odr constant i32 4
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE8 = linkonce_odr global {{.*}} { i32* @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7 }
|
||||||
|
// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE9 = linkonce_odr global {{.*}} { {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6, {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE8 }
|
||||||
|
// CHECK: @_ZN24VariableTemplateWithPack1pE = global {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE9
|
||||||
|
namespace VariableTemplateWithPack {
|
||||||
|
struct A {
|
||||||
|
const int &r;
|
||||||
|
};
|
||||||
|
struct S {
|
||||||
|
A &&a, &&b, &&c, &&d;
|
||||||
|
};
|
||||||
|
template <int... N>
|
||||||
|
S &&s = {A{N}...};
|
||||||
|
S *p = &s<1, 2, 3, 4>;
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
|
// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b
|
||||||
|
|
||||||
// CHECK: define
|
// CHECK: define
|
||||||
|
|
|
@ -21,7 +21,7 @@ template<typename T> thread_local int V<T>::m = g();
|
||||||
// CHECK: @e = global i32 0
|
// CHECK: @e = global i32 0
|
||||||
int e = V<int>::m;
|
int e = V<int>::m;
|
||||||
|
|
||||||
// CHECK: @_ZN1VIiE1mE = weak_odr thread_local global i32 0
|
// CHECK: @_ZN1VIiE1mE = linkonce_odr thread_local global i32 0
|
||||||
|
|
||||||
// CHECK: @_ZZ1fvE1n = internal thread_local global i32 0
|
// CHECK: @_ZZ1fvE1n = internal thread_local global i32 0
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ int e = V<int>::m;
|
||||||
|
|
||||||
// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global
|
// CHECK: @_ZZ8tls_dtorvE1u = internal thread_local global
|
||||||
// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
|
// CHECK: @_ZGVZ8tls_dtorvE1u = internal thread_local global i8 0
|
||||||
// CHECK: @_ZGRZ8tls_dtorvE1u = private thread_local global
|
// CHECK: @_ZGRZ8tls_dtorvE1u = internal thread_local global
|
||||||
|
|
||||||
// CHECK: @_ZGVN1VIiE1mE = weak_odr thread_local global i64 0
|
// CHECK: @_ZGVN1VIiE1mE = linkonce_odr thread_local global i64 0
|
||||||
|
|
||||||
// CHECK: @__tls_guard = internal thread_local global i8 0
|
// CHECK: @__tls_guard = internal thread_local global i8 0
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ int e = V<int>::m;
|
||||||
// CHECK: @_ZTH1a = alias void ()* @__tls_init
|
// CHECK: @_ZTH1a = alias void ()* @__tls_init
|
||||||
// CHECK: @_ZTHL1d = alias internal void ()* @__tls_init
|
// CHECK: @_ZTHL1d = alias internal void ()* @__tls_init
|
||||||
// CHECK: @_ZTHN1U1mE = alias void ()* @__tls_init
|
// CHECK: @_ZTHN1U1mE = alias void ()* @__tls_init
|
||||||
// CHECK: @_ZTHN1VIiE1mE = alias weak_odr void ()* @__tls_init
|
// CHECK: @_ZTHN1VIiE1mE = alias linkonce_odr void ()* @__tls_init
|
||||||
|
|
||||||
|
|
||||||
// Individual variable initialization functions:
|
// Individual variable initialization functions:
|
||||||
|
|
|
@ -18,7 +18,7 @@ int init_arr();
|
||||||
template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
|
template<typename T> template<typename U> template<typename V> int Outer<T>::Inner<U>::arr[sizeof(T) + sizeof(U) + sizeof(V)] = { init_arr() };
|
||||||
int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
|
int *p = Outer<char[100]>::Inner<char[20]>::arr<char[3]>;
|
||||||
|
|
||||||
// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global [123 x i32] zeroinitializer
|
// CHECK: @_ZN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global [123 x i32] zeroinitializer
|
||||||
// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = weak_odr global
|
// CHECK: @_ZGVN5OuterIA100_cE5InnerIA20_cE3arrIA3_cEE = linkonce_odr global
|
||||||
|
|
||||||
// CHECK: call {{.*}}@_Z8init_arrv
|
// CHECK: call {{.*}}@_Z8init_arrv
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// rdar: // 8562966
|
// rdar: // 8562966
|
||||||
// pr8409
|
// pr8409
|
||||||
|
|
||||||
// CHECK: @_ZN1CIiE11needs_guardE = weak_odr global
|
// CHECK: @_ZN1CIiE11needs_guardE = linkonce_odr global
|
||||||
// CHECK: @_ZGVN1CIiE11needs_guardE = weak_odr global
|
// CHECK: @_ZGVN1CIiE11needs_guardE = linkonce_odr global
|
||||||
|
|
||||||
struct K
|
struct K
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,8 +16,8 @@ struct X1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X2* null, align 8
|
// CHECK: @_ZN2X1I2X2I1BEE8instanceE = linkonce_odr global %struct.X2* null, align 8
|
||||||
// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X2* null, align 8
|
// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = linkonce_odr global %struct.X2* null, align 8
|
||||||
template<class T> T & X1<T>::instance = X1<T>::get();
|
template<class T> T & X1<T>::instance = X1<T>::get();
|
||||||
|
|
||||||
class A { };
|
class A { };
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
// CHECK-NOT: @_ZTVN5test018stdio_sync_filebufIA2_iEE
|
// CHECK-NOT: @_ZTVN5test018stdio_sync_filebufIA2_iEE
|
||||||
// CHECK: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr unnamed_addr constant
|
// CHECK: @_ZTVN5test018stdio_sync_filebufIA3_iEE = weak_odr unnamed_addr constant
|
||||||
|
|
||||||
// CHECK: @_ZN7PR100011SIiE3arrE = weak_odr global [3 x i32]
|
// CHECK: @_ZN7PR100011SIiE3arrE = linkonce_odr global [3 x i32]
|
||||||
// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = weak_odr global [3 x i32]A
|
// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = linkonce_odr global [3 x i32]A
|
||||||
|
|
||||||
// CHECK: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr unnamed_addr constant
|
// CHECK: @_ZTVN5test018stdio_sync_filebufIA4_iEE = linkonce_odr unnamed_addr constant
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ template<typename T> int S<T>::n = 5;
|
||||||
int f() {
|
int f() {
|
||||||
// Make sure that the reference here is enough to trigger the instantiation of
|
// Make sure that the reference here is enough to trigger the instantiation of
|
||||||
// the static data member.
|
// the static data member.
|
||||||
// CHECK: @_ZN1SIiE1nE = weak_odr global i32 5
|
// CHECK: @_ZN1SIiE1nE = linkonce_odr global i32 5
|
||||||
int a[S<int>::n];
|
int a[S<int>::n];
|
||||||
return sizeof a;
|
return sizeof a;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue