diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-13 07:42:10 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-13 07:42:10 +0000 |
commit | 5c5be6b2f7fc00255d6169277354d040c74b3e4b (patch) | |
tree | 1bd5e93fa744a9eca5899a569fa680e2e6a65cdb /clang/lib/Sema | |
parent | f3be557159c2eed6eeca008547cf5359960d62d0 (diff) | |
download | bcm5719-llvm-5c5be6b2f7fc00255d6169277354d040c74b3e4b.tar.gz bcm5719-llvm-5c5be6b2f7fc00255d6169277354d040c74b3e4b.zip |
[c++20] P1064R0: Allow virtual function calls in constant expression
evaluation.
llvm-svn: 360559
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 38 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 12 |
2 files changed, 34 insertions, 16 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index afd50f1438e..1da2ca8ca5f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1596,6 +1596,9 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { // The definition of a constexpr constructor shall satisfy the following // constraints: // - the class shall not have any virtual base classes; + // + // FIXME: This only applies to constructors, not arbitrary member + // functions. const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) @@ -1612,21 +1615,25 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following // constraints: - // - it shall not be virtual; + // - it shall not be virtual; (removed in C++20) const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); if (Method && Method->isVirtual()) { - Method = Method->getCanonicalDecl(); - Diag(Method->getLocation(), diag::err_constexpr_virtual); - - // If it's not obvious why this function is virtual, find an overridden - // function which uses the 'virtual' keyword. - const CXXMethodDecl *WrittenVirtual = Method; - while (!WrittenVirtual->isVirtualAsWritten()) - WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); - if (WrittenVirtual != Method) - Diag(WrittenVirtual->getLocation(), - diag::note_overridden_virtual_function); - return false; + if (getLangOpts().CPlusPlus2a) { + Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual); + } else { + Method = Method->getCanonicalDecl(); + Diag(Method->getLocation(), diag::err_constexpr_virtual); + + // If it's not obvious why this function is virtual, find an overridden + // function which uses the 'virtual' keyword. + const CXXMethodDecl *WrittenVirtual = Method; + while (!WrittenVirtual->isVirtualAsWritten()) + WrittenVirtual = *WrittenVirtual->begin_overridden_methods(); + if (WrittenVirtual != Method) + Diag(WrittenVirtual->getLocation(), + diag::note_overridden_virtual_function); + return false; + } } // - its return type shall be a literal type; @@ -15197,7 +15204,8 @@ void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, } void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, - const CXXRecordDecl *RD) { + const CXXRecordDecl *RD, + bool ConstexprOnly) { // Mark all functions which will appear in RD's vtable as used. CXXFinalOverriderMap FinalOverriders; RD->getFinalOverriders(FinalOverriders); @@ -15212,7 +15220,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, // C++ [basic.def.odr]p2: // [...] A virtual member function is used if it is not pure. [...] - if (!Overrider->isPure()) + if (!Overrider->isPure() && (!ConstexprOnly || Overrider->isConstexpr())) MarkFunctionReferenced(Loc, Overrider); } } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index edc281cad6e..55d1d94bd82 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2082,6 +2082,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, LateInstantiatedAttrVec LateAttrs; Instantiator.enableLateAttributeInstantiation(&LateAttrs); + bool MightHaveConstexprVirtualFunctions = false; for (auto *Member : Pattern->decls()) { // Don't instantiate members not belonging in this semantic context. // e.g. for: @@ -2128,6 +2129,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->setInvalidDecl(); break; } + } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewMember)) { + if (MD->isConstexpr() && !MD->getFriendObjectKind() && + (MD->isVirtualAsWritten() || Instantiation->getNumBases())) + MightHaveConstexprVirtualFunctions = true; } if (NewMember->isInvalidDecl()) @@ -2220,9 +2225,14 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Consumer.HandleTagDeclDefinition(Instantiation); // Always emit the vtable for an explicit instantiation definition - // of a polymorphic class template specialization. + // of a polymorphic class template specialization. Otherwise, eagerly + // instantiate only constexpr virtual functions in preparation for their use + // in constant evaluation. if (TSK == TSK_ExplicitInstantiationDefinition) MarkVTableUsed(PointOfInstantiation, Instantiation, true); + else if (MightHaveConstexprVirtualFunctions) + MarkVirtualMembersReferenced(PointOfInstantiation, Instantiation, + /*ConstexprOnly*/ true); } return Instantiation->isInvalidDecl(); |