Implement C++17 P0386R2, inline variables. (The 'inline' specifier gives a
variable weak discardable linkage and partially-ordered initialization, and is
implied for constexpr static data members.)
llvm-svn: 273754
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 58c0ab0..dbb8c6e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3881,11 +3881,12 @@
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
- // Delay instantiation of the initializer for variable templates until a
- // definition of the variable is needed. We need it right away if the type
- // contains 'auto'.
+ // Delay instantiation of the initializer for variable templates or inline
+ // static data members until a definition of the variable is needed. We need
+ // it right away if the type contains 'auto'.
if ((!isa<VarTemplateSpecializationDecl>(NewVar) &&
- !InstantiatingVarTemplate) ||
+ !InstantiatingVarTemplate &&
+ !(OldVar->isInline() && OldVar->isThisDeclarationADefinition())) ||
NewVar->getType()->isUndeducedType())
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
@@ -3901,6 +3902,13 @@
void Sema::InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs) {
+ // We propagate the 'inline' flag with the initializer, because it
+ // would otherwise imply that the variable is a definition for a
+ // non-static data member.
+ if (OldVar->isInlineSpecified())
+ Var->setInlineSpecified();
+ else if (OldVar->isInline())
+ Var->setImplicitlyInline();
if (Var->getAnyInitializer())
// We already have an initializer in the class.
@@ -4083,7 +4091,7 @@
assert(PatternDecl && "data member was not instantiated from a template?");
assert(PatternDecl->isStaticDataMember() && "not a static data member?");
- Def = PatternDecl->getOutOfLineDefinition();
+ Def = PatternDecl->getDefinition();
}
// FIXME: Check that the definition is visible before trying to instantiate
@@ -4181,11 +4189,16 @@
LocalInstantiationScope Local(*this);
VarDecl *OldVar = Var;
- if (!VarSpec)
+ if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
+ // We're instantiating an inline static data member whose definition was
+ // provided inside the class.
+ // FIXME: Update record?
+ InstantiateVariableInitializer(Var, Def, TemplateArgs);
+ } else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
TemplateArgs));
- else if (Var->isStaticDataMember() &&
- Var->getLexicalDeclContext()->isRecord()) {
+ } else if (Var->isStaticDataMember() &&
+ Var->getLexicalDeclContext()->isRecord()) {
// We need to instantiate the definition of a static data member template,
// and all we have is the in-class declaration of it. Instantiate a separate
// declaration of the definition.