r274416 - PR28394: For compatibility with c++11 and c++14, if a static constexpr data
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 1 18:32:17 PDT 2016
Author: rsmith
Date: Fri Jul 1 20:32:16 2016
New Revision: 274416
URL: http://llvm.org/viewvc/llvm-project?rev=274416&view=rev
Log:
PR28394: For compatibility with c++11 and c++14, if a static constexpr data
member is redundantly redeclared outside the class definition in code built in
c++17 mode, ensure we emit a non-discardable definition of the data member for
c++11 and c++14 compilations to use.
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/test/CodeGenCXX/cxx1z-inline-variables.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=274416&r1=274415&r2=274416&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jul 1 20:32:16 2016
@@ -2528,7 +2528,21 @@ public:
/// \brief Returns true if this is an inline-initialized static data member
/// which is treated as a definition for MSVC compatibility.
bool isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const;
-
+
+ enum class InlineVariableDefinitionKind {
+ None, ///< Not an inline variable.
+ Weak, ///< Weak definition of inline variable.
+ WeakUnknown, ///< Weak for now, might become strong later in this TU.
+ Strong ///< Strong definition.
+ };
+ /// \brief Determine whether a definition of this inline variable should
+ /// be treated as a weak or strong definition. For compatibility with
+ /// C++14 and before, for a constexpr static data member, if there is an
+ /// out-of-line declaration of the member, we may promote it from weak to
+ /// strong.
+ InlineVariableDefinitionKind
+ getInlineVariableDefinitionKind(const VarDecl *VD) const;
+
private:
const ASTRecordLayout &
getObjCLayout(const ObjCInterfaceDecl *D,
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=274416&r1=274415&r2=274416&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jul 1 20:32:16 2016
@@ -5146,6 +5146,27 @@ bool ASTContext::isMSStaticDataMemberInl
!VD->getFirstDecl()->isOutOfLine() && VD->getFirstDecl()->hasInit();
}
+ASTContext::InlineVariableDefinitionKind
+ASTContext::getInlineVariableDefinitionKind(const VarDecl *VD) const {
+ if (!VD->isInline())
+ return InlineVariableDefinitionKind::None;
+
+ // In almost all cases, it's a weak definition.
+ auto *First = VD->getFirstDecl();
+ if (!First->isConstexpr() || First->isInlineSpecified() ||
+ !VD->isStaticDataMember())
+ return InlineVariableDefinitionKind::Weak;
+
+ // If there's a file-context declaration in this translation unit, it's a
+ // non-discardable definition.
+ for (auto *D : VD->redecls())
+ if (D->getLexicalDeclContext()->isFileContext())
+ return InlineVariableDefinitionKind::Strong;
+
+ // If we've not seen one yet, we don't know.
+ return InlineVariableDefinitionKind::WeakUnknown;
+}
+
static inline
std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
@@ -8494,9 +8515,21 @@ static GVALinkage basicGVALinkageForVari
if (Context.isMSStaticDataMemberInlineDefinition(VD))
return GVA_DiscardableODR;
- GVALinkage StrongLinkage = GVA_StrongExternal;
- if (VD->isInline())
+ // Most non-template variables have strong linkage; inline variables are
+ // linkonce_odr or (occasionally, for compatibility) weak_odr.
+ GVALinkage StrongLinkage;
+ switch (Context.getInlineVariableDefinitionKind(VD)) {
+ case ASTContext::InlineVariableDefinitionKind::None:
+ StrongLinkage = GVA_StrongExternal;
+ break;
+ case ASTContext::InlineVariableDefinitionKind::Weak:
+ case ASTContext::InlineVariableDefinitionKind::WeakUnknown:
StrongLinkage = GVA_DiscardableODR;
+ break;
+ case ASTContext::InlineVariableDefinitionKind::Strong:
+ StrongLinkage = GVA_StrongODR;
+ break;
+ }
switch (VD->getTemplateSpecializationKind()) {
case TSK_Undeclared:
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=274416&r1=274415&r2=274416&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jul 1 20:32:16 2016
@@ -1447,6 +1447,12 @@ bool CodeGenModule::MayBeEmittedEagerly(
// Implicit template instantiations may change linkage if they are later
// explicitly instantiated, so they should not be emitted eagerly.
return false;
+ if (const auto *VD = dyn_cast<VarDecl>(Global))
+ if (Context.getInlineVariableDefinitionKind(VD) ==
+ ASTContext::InlineVariableDefinitionKind::WeakUnknown)
+ // A definition of an inline constexpr static data member may change
+ // linkage later if it's redeclared outside the class.
+ return false;
// If OpenMP is enabled and threadprivates must be generated like TLS, delay
// codegen for global variables, because they may be marked as threadprivate.
if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS &&
@@ -1595,8 +1601,14 @@ void CodeGenModule::EmitGlobal(GlobalDec
VD->hasAttr<CUDADeviceAttr>());
if (!MustEmitForCuda &&
VD->isThisDeclarationADefinition() != VarDecl::Definition &&
- !Context.isMSStaticDataMemberInlineDefinition(VD))
+ !Context.isMSStaticDataMemberInlineDefinition(VD)) {
+ // If this declaration may have caused an inline variable definition to
+ // change linkage, make sure that it's emitted.
+ if (Context.getInlineVariableDefinitionKind(VD) ==
+ ASTContext::InlineVariableDefinitionKind::Strong)
+ GetAddrOfGlobalVar(VD);
return;
+ }
}
// Defer code generation to first use when possible, e.g. if this is an inline
Modified: cfe/trunk/test/CodeGenCXX/cxx1z-inline-variables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-inline-variables.cpp?rev=274416&r1=274415&r2=274416&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-inline-variables.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-inline-variables.cpp Fri Jul 1 20:32:16 2016
@@ -24,6 +24,26 @@ int a = f();
inline int b = f();
int c = f();
+// For compatibility with C++11 and C++14, an out-of-line declaration of a
+// static constexpr local variable promotes the variable to weak_odr.
+struct compat {
+ static constexpr int a = 1;
+ static constexpr int b = 2;
+ static constexpr int c = 3;
+ static inline constexpr int d = 4;
+};
+const int &compat_use_before_redecl = compat::b;
+const int compat::a;
+const int compat::b;
+const int compat::c;
+const int compat::d;
+const int &compat_use_after_redecl1 = compat::c;
+const int &compat_use_after_redecl2 = compat::d;
+// CHECK: @_ZN6compat1bE = weak_odr constant i32 2
+// CHECK: @_ZN6compat1aE = weak_odr constant i32 1
+// CHECK: @_ZN6compat1cE = weak_odr constant i32 3
+// CHECK: @_ZN6compat1dE = linkonce_odr constant i32 4
+
template<typename T> struct X {
static int a;
static inline int b;
More information about the cfe-commits
mailing list