// TSK_ExplicitInstantiationDefinition
if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
TSK == TSK_ExplicitInstantiationDefinition)
+ // FIXME: Need to notify the ASTMutationListener that we did this.
Def->setTemplateSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
- if (TSK == TSK_ExplicitInstantiationDefinition)
+ if (Specialization->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
// C++0x [temp.explicit]p2:
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
+ // FIXME: We need to notify the ASTMutationListener that we did all of these
+ // things, in case we have an explicit instantiation definition in a PCM, a
+ // module, or preamble, and the declaration is in an imported AST.
assert(
(TSK == TSK_ExplicitInstantiationDefinition ||
TSK == TSK_ExplicitInstantiationDeclaration ||
SuppressNew) ||
SuppressNew)
continue;
-
- if (Function->isDefined())
+
+ // C++11 [temp.explicit]p8:
+ // An explicit instantiation definition that names a class template
+ // specialization explicitly instantiates the class template
+ // specialization and is only an explicit instantiation definition
+ // of members whose definition is visible at the point of
+ // instantiation.
+ if (TSK == TSK_ExplicitInstantiationDefinition && !Pattern->isDefined())
continue;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
- // C++0x [temp.explicit]p8:
- // An explicit instantiation definition that names a class template
- // specialization explicitly instantiates the class template
- // specialization and is only an explicit instantiation definition
- // of members whose definition is visible at the point of
- // instantiation.
- if (!Pattern->isDefined())
- continue;
-
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-
+ Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+
+ if (Function->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Function));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition) {
InstantiateFunctionDefinition(PointOfInstantiation, Function);
- } else {
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- if (TSK == TSK_ImplicitInstantiation)
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Function, PointOfInstantiation));
+ } else if (TSK == TSK_ImplicitInstantiation) {
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
}
}
} else if (auto *Var = dyn_cast<VarDecl>(D)) {
-// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-OPT
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -O3 -disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT
// This check logically is attached to 'template int S<int>::i;' below.
// CHECK: @_ZN1SIiE1iE = weak_odr global i32
// CHECK-LABEL: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
template struct plus<int, long, long>;
+namespace EarlyInstantiation {
+ // Check that we emit definitions if we instantiate a function definition before
+ // it gets explicitly instantiatied.
+ template<typename T> struct S {
+ constexpr int constexpr_function() { return 0; }
+ auto deduced_return_type() { return 0; }
+ };
+
+ // From an implicit instantiation.
+ constexpr int a = S<char>().constexpr_function();
+ int b = S<char>().deduced_return_type();
+
+ // From an explicit instantiation declaration.
+ extern template struct S<int>;
+ constexpr int c = S<int>().constexpr_function();
+ int d = S<int>().deduced_return_type();
+
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE18constexpr_functionEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE19deduced_return_typeEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE18constexpr_functionEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE19deduced_return_typeEv(
+ template struct S<char>;
+ template struct S<int>;
+
+ template<typename T> constexpr int constexpr_function() { return 0; }
+ template<typename T> auto deduced_return_type() { return 0; }
+
+ // From an implicit instantiation.
+ constexpr int e = constexpr_function<char>();
+ int f = deduced_return_type<char>();
+
+ // From an explicit instantiation declaration.
+ extern template int constexpr_function<int>();
+ extern template auto deduced_return_type<int>();
+ constexpr int g = constexpr_function<int>();
+ int h = deduced_return_type<int>();
+
+ // The FIXMEs below are for PR19551.
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIcEEiv(
+ // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIcEEiv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIiEEiv(
+ // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIiEEiv(
+ template int constexpr_function<char>();
+ // FIXME template auto deduced_return_type<char>();
+ template int constexpr_function<int>();
+ // FIXME template auto deduced_return_type<int>();
+}
+
+namespace LateInstantiation {
+ // Check that we downgrade the linkage to available_externally if we see an
+ // explicit instantiation declaration after the function template is
+ // instantiated.
+ template<typename T> struct S { constexpr int f() { return 0; } };
+ template<typename T> constexpr int f() { return 0; }
+
+ // Trigger eager instantiation of the function definitions.
+ int a, b = S<char>().f() + f<char>() + a;
+ int c, d = S<int>().f() + f<int>() + a;
+
+ // Don't allow some of those definitions to be emitted.
+ extern template struct S<int>;
+ extern template int f<int>();
+
+ // Check that we declare, define, or provide an available-externally
+ // definition as appropriate.
+ // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1SIcE1fEv(
+ // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1fIcEEiv(
+ // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1SIiE1fEv(
+ // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1fIiEEiv(
+ // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1SIiE1fEv(
+ // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1fIiEEiv(
+}
+
// Check that we emit definitions from explicit instantiations even when they
// occur prior to the definition itself.
template <typename T> struct S {
}
template<typename T> struct MergePatternDecl;
+
+extern template struct ExplicitInstantiation<false, false>;
+extern template struct ExplicitInstantiation<false, true>;
+extern template struct ExplicitInstantiation<true, false>;
+extern template struct ExplicitInstantiation<true, true>;
+
+void useExplicitInstantiation() {
+ ExplicitInstantiation<true, false>().f();
+ ExplicitInstantiation<true, true>().f();
+}
template<typename T> struct Outer {
struct Inner {};
};
+
+template<bool, bool> struct ExplicitInstantiation {
+ void f() {}
+};
redeclDefinitionEmit();
}
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+// CHECK: declare {{.*}}@_ZN21ExplicitInstantiationILb1ELb0EE1fEv(
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb1ELb1EE1fEv(
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+
// These three are all the same type.
typedef OuterIntInner_left OuterIntInner;
typedef OuterIntInner_right OuterIntInner;
void f(Type);
};
template<typename T> void MergePatternDecl<T>::f(Type type) {}
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb0ELb1EE1fEv(
+template struct ExplicitInstantiation<false, true>;
+template struct ExplicitInstantiation<true, true>;