diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 |
4 files changed, 19 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 5b4dc5ff0ab..127d7df348e 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2770,10 +2770,19 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, // We can devirtualize calls on an object accessed by a class member access // expression, since by C++11 [basic.life]p6 we know that it can't refer to - // a derived class object constructed in the same location. + // a derived class object constructed in the same location. However, we avoid + // devirtualizing a call to a template function that we could instantiate + // implicitly, but have not decided to do so. This is needed because if this + // function does not get instantiated, the devirtualization will create a + // direct call to a function whose body may not exist. In contrast, calls to + // template functions that are not defined in this TU are allowed to be + // devirtualized under assumption that it is user responsibility to + // instantiate them in some other TU. if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) - return VD->getType()->isRecordType(); + return VD->getType()->isRecordType() && + (MD->instantiationIsPending() || MD->isDefined() || + !MD->isImplicitlyInstantiable()); // Likewise for calls on an object accessed by a (non-reference) pointer to // member access. diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index e7b0914641f..007a5e483e6 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -740,6 +740,9 @@ void Sema::ActOnEndOfTranslationUnit() { // Load pending instantiations from the external source. SmallVector<PendingImplicitInstantiation, 4> Pending; ExternalSource->ReadPendingInstantiations(Pending); + for (auto PII : Pending) + if (auto Func = dyn_cast<FunctionDecl>(PII.first)) + Func->setInstantiationIsPending(true); PendingInstantiations.insert(PendingInstantiations.begin(), Pending.begin(), Pending.end()); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 75a6903392e..f49df6b3216 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13732,6 +13732,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // call to such a function. InstantiateFunctionDefinition(PointOfInstantiation, Func); else { + Func->setInstantiationIsPending(true); PendingInstantiations.push_back(std::make_pair(Func, PointOfInstantiation)); // Notify the consumer that a function was implicitly instantiated. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 148ce24293a..c58122cd271 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3782,6 +3782,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Try again at the end of the translation unit (at which point a // definition will be required). assert(!Recursive); + Function->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); } else if (TSK == TSK_ImplicitInstantiation) { @@ -3801,6 +3802,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Postpone late parsed template instantiations. if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { + Function->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); return; @@ -5146,6 +5148,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired, true); + if (Function->isDefined()) + Function->setInstantiationIsPending(false); continue; } |