Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1883,6 +1883,29 @@ CanQualType getFromTargetType(unsigned Type) const; TypeInfo getTypeInfoImpl(const Type *T) const; + + //===--------------------------------------------------------------------===// + // Template instantiation. + //===--------------------------------------------------------------------===// +public: + + /// Helper class that provides interface to template instantiation facility. + class InstantiationHelper { + public: + virtual ~InstantiationHelper(); + virtual bool instantiateFunctionDefinition( + SourceLocation PointOfInstantiation, + FunctionDecl *Function) = 0; + }; + + void setInstantiator(InstantiationHelper *Helper); + InstantiationHelper *removeInstantiator(); + bool instantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function); +private: + InstantiationHelper *Instantiator = nullptr; + + //===--------------------------------------------------------------------===// // Type Predicates. //===--------------------------------------------------------------------===// Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -9596,6 +9596,28 @@ return (*AddrSpaceMap)[AS]; } +ASTContext::InstantiationHelper::~InstantiationHelper() { +} + +void ASTContext::setInstantiator(ASTContext::InstantiationHelper *Inst) { + Instantiator = Inst; +} + +ASTContext::InstantiationHelper *ASTContext::removeInstantiator() { + InstantiationHelper *Res = Instantiator; + Instantiator = nullptr; + return Res; +} + +bool ASTContext::instantiateFunctionDefinition( + SourceLocation PointOfInstantiation, + FunctionDecl *Function) { + if (!Instantiator) + return false; + return Instantiator->instantiateFunctionDefinition(PointOfInstantiation, + Function); +} + // Explicitly instantiate this in case a Redeclarable is used from a TU that // doesn't include ASTContext.h template Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -2564,6 +2564,30 @@ return false; } +/// Returns body of the function described by the specified declaration, +/// instantiating its definition if necessary. +/// +/// \param[in] FD The function which body is retrieved. +/// \param[in] Loc Location that becomes a point of instantiation. +/// \param[out] Definition The redeclaration that provides the body. +/// +/// Behaves like FinctionDecl::getBody, but also can implicitly instantiate +/// function body. +/// +static Stmt *getFunctionBody(const FunctionDecl *FD, SourceLocation Loc, + const FunctionDecl *&Definition) { + Definition = nullptr; + Stmt *Body = FD->getBody(Definition); + // Try instantiation function body is possible. Do it only for constexpr + // declarations, others are not allowed in constant expressions. + if (!Body && FD->isImplicitlyInstantiable() && FD->isConstexpr()) { + FD->getASTContext().instantiateFunctionDefinition(Loc, + const_cast(FD)); + Body = FD->getBody(Definition); + } + return Body; +} + /// Kinds of access we can perform on an object, for diagnostics. enum AccessKinds { AK_Read, @@ -4715,7 +4739,7 @@ return Error(E, diag::note_constexpr_virtual_call); const FunctionDecl *Definition = nullptr; - Stmt *Body = FD->getBody(Definition); + Stmt *Body = getFunctionBody(FD, Callee->getLocStart(), Definition); if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) || !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body, Info, @@ -6285,7 +6309,7 @@ } const FunctionDecl *Definition = nullptr; - auto Body = FD->getBody(Definition); + Stmt *Body = getFunctionBody(FD, E->getLocStart(), Definition); if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; @@ -6317,7 +6341,7 @@ return false; const FunctionDecl *Definition = nullptr; - auto Body = FD->getBody(Definition); + Stmt *Body = getFunctionBody(FD, E->getExprLoc(), Definition); if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body)) return false; @@ -10714,8 +10738,10 @@ HandleConstructorCall(&VIE, This, Args, CD, Info, Scratch); } else { SourceLocation Loc = FD->getLocation(); + const FunctionDecl *Definition; + Stmt *Body = getFunctionBody(FD, Loc, Definition); HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr, - Args, FD->getBody(), Info, Scratch, nullptr); + Args, Body, Info, Scratch, nullptr); } return Diags.empty(); Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -113,6 +113,20 @@ } // end namespace sema } // end namespace clang +namespace { +class SemaTemplateInstantiator : public ASTContext::InstantiationHelper { + Sema &S; +public: + ~SemaTemplateInstantiator() {} + SemaTemplateInstantiator(Sema &S) : S(S) {} + bool instantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function) override { + S.InstantiateFunctionDefinition(PointOfInstantiation, Function); + return Function->hasBody(); + } +}; +} + Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : ExternalSource(nullptr), isMultiplexExternalSource(false), @@ -171,6 +185,8 @@ SemaPPCallbackHandler = Callbacks.get(); PP.addPPCallbacks(std::move(Callbacks)); SemaPPCallbackHandler->set(*this); + + Context.setInstantiator(new SemaTemplateInstantiator(*this)); } void Sema::addImplicitTypedef(StringRef Name, QualType T) { @@ -359,6 +375,9 @@ // by the preprocessor. SemaPPCallbackHandler->reset(); + ASTContext::InstantiationHelper *Inst = Context.removeInstantiator(); + delete Inst; + assert(DelayedTypos.empty() && "Uncorrected typos!"); } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13635,11 +13635,6 @@ CodeSynthesisContexts.size()) 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(PointOfInstantiation, Func); else { Func->setInstantiationIsPending(true); PendingInstantiations.push_back(std::make_pair(Func, Index: test/SemaTemplate/constexpr-instantiate.cpp =================================================================== --- test/SemaTemplate/constexpr-instantiate.cpp +++ test/SemaTemplate/constexpr-instantiate.cpp @@ -259,3 +259,9 @@ } static_assert(fact(0) == 1, ""); } + +namespace CWG_1581 { + template struct U {}; + template constexpr int h(T) { return T::error; } // expected-error{{type 'int' cannot be used prior to '::' because it has no members}} + int k2 = sizeof(U<0 && h(0)>); // expected-note{{in instantiation of function template specialization 'CWG_1581::h' requested here}} +} Index: test/SemaTemplate/instantiate-constexpr-function.cpp =================================================================== --- /dev/null +++ test/SemaTemplate/instantiate-constexpr-function.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++14 -verify %s +// expected-no-diagnostics + +template constexpr void func_01(T) { + func_01(0); +} + + +template constexpr unsigned func_02a() { + return sizeof(T); +} +template constexpr T func_02b(T x) { + return x + func_02a(); +} +constexpr long val_02 = func_02b(14L); + + +template constexpr T func_03(T) { + return T::xyz; +} +template T func_04(T x) { + return x; +} +template<> constexpr long func_04(long x) { + return 66; +} +constexpr long var_04 = func_04(0L); +static_assert(var_04 == 66, "error"); + + +template struct C_05 { + constexpr T func_05() { return T::xyz; } +}; +C_05 var_05;