Func->setReferenced();
- if (Func->isUsed(false))
+ // Don't mark this function as used multiple times, unless it's a constexpr
+ // function which we need to instantiate.
+ if (Func->isUsed(false) &&
+ !(Func->isConstexpr() && !Func->getBody() &&
+ Func->isImplicitlyInstantiable()))
return;
if (!IsPotentiallyEvaluatedContext(*this))
// class templates.
if (Func->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
+ SourceLocation PointOfInstantiation = Loc;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Func->getTemplateSpecializationInfo()) {
if (SpecInfo->getPointOfInstantiation().isInvalid())
SpecInfo->setPointOfInstantiation(Loc);
else if (SpecInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation)
+ == TSK_ImplicitInstantiation) {
AlreadyInstantiated = true;
+ PointOfInstantiation = SpecInfo->getPointOfInstantiation();
+ }
} else if (MemberSpecializationInfo *MSInfo
= Func->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(Loc);
else if (MSInfo->getTemplateSpecializationKind()
- == TSK_ImplicitInstantiation)
+ == TSK_ImplicitInstantiation) {
AlreadyInstantiated = true;
+ PointOfInstantiation = MSInfo->getPointOfInstantiation();
+ }
}
- if (!AlreadyInstantiated) {
+ if (!AlreadyInstantiated || Func->isConstexpr()) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
- PendingLocalImplicitInstantiations.push_back(std::make_pair(Func,
- Loc));
- else if (Func->getTemplateInstantiationPattern()->isConstexpr())
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Func, PointOfInstantiation));
+ else if (Func->isConstexpr())
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
- InstantiateFunctionDefinition(Loc, Func);
+ InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
- PendingInstantiations.push_back(std::make_pair(Func, Loc));
+ PendingInstantiations.push_back(std::make_pair(Func,
+ PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
Consumer.HandleCXXImplicitFunctionInstantiation(Func);
}
--- /dev/null
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace UseBeforeDefinition {
+ struct A {
+ template<typename T> static constexpr T get() { return T(); }
+ // ok, not a constant expression.
+ int n = get<int>();
+ };
+
+ // ok, constant expression.
+ constexpr int j = A::get<int>();
+
+ template<typename T> constexpr int consume(T);
+ // ok, not a constant expression.
+ const int k = consume(0); // expected-note {{here}}
+
+ template<typename T> constexpr int consume(T) { return 0; }
+ // ok, constant expression.
+ constexpr int l = consume(0);
+
+ constexpr int m = k; // expected-error {{constant expression}} expected-note {{initializer of 'k'}}
+}
+
+namespace IntegralConst {
+ template<typename T> constexpr T f(T n) { return n; }
+ enum E {
+ v = f(0), w = f(1) // ok
+ };
+ static_assert(w == 1, "");
+
+ char arr[f('x')]; // ok
+ static_assert(sizeof(arr) == 'x', "");
+}
+
+namespace ConvertedConst {
+ template<typename T> constexpr T f(T n) { return n; }
+ int f() {
+ switch (f()) {
+ case f(4): return 0;
+ }
+ return 1;
+ }
+}
+
+namespace OverloadResolution {
+ template<typename T> constexpr T f(T t) { return t; }
+
+ template<int n> struct S { };
+
+ template<typename T> auto g(T t) -> S<f(sizeof(T))> &;
+ char &f(...);
+
+ template<typename T> auto h(T t[f(sizeof(T))]) -> decltype(&*t) {
+ return t;
+ }
+
+ S<4> &k = g(0);
+ int *p, *q = h(p);
+}