From: Richard Smith Date: Tue, 14 Feb 2012 22:25:15 +0000 (+0000) Subject: If a constexpr function template specialization is referenced, and then the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=57b9c4e9d85971e20ab0dac3eadabae672c43c62;p=clang If a constexpr function template specialization is referenced, and then the template is defined, and then the specialization is referenced again, don't forget to instantiate the template on the second reference. Use the source location of the first reference as the point of instantiation, though. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150518 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 371a4e39eb..050386e299 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9404,7 +9404,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { 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)) @@ -9455,34 +9459,40 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { // 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(Func->getDeclContext()) && cast(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); } diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp new file mode 100644 index 0000000000..69ac0e476b --- /dev/null +++ b/test/SemaTemplate/constexpr-instantiate.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +namespace UseBeforeDefinition { + struct A { + template static constexpr T get() { return T(); } + // ok, not a constant expression. + int n = get(); + }; + + // ok, constant expression. + constexpr int j = A::get(); + + template constexpr int consume(T); + // ok, not a constant expression. + const int k = consume(0); // expected-note {{here}} + + template 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 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 constexpr T f(T n) { return n; } + int f() { + switch (f()) { + case f(4): return 0; + } + return 1; + } +} + +namespace OverloadResolution { + template constexpr T f(T t) { return t; } + + template struct S { }; + + template auto g(T t) -> S &; + char &f(...); + + template auto h(T t[f(sizeof(T))]) -> decltype(&*t) { + return t; + } + + S<4> &k = g(0); + int *p, *q = h(p); +}