summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2019-05-13 13:19:09 +0000
committerHans Wennborg <hans@hanshq.net>2019-05-13 13:19:09 +0000
commit24e6d2a7b6f041a6df9e61cf9cecfc15c1f7ccac (patch)
treefc365619cc8ebc19a6743544184f14d4674f3321
parentf585a602f52c5f1c02c0c39400a2ca273e3a51b1 (diff)
downloadclang-24e6d2a7b6f041a6df9e61cf9cecfc15c1f7ccac.tar.gz
Revert r360559 "[c++20] P1064R0: Allow virtual function calls in constant expression evaluation."
This caused Chromium builds to hit the new "can't handle virtual calls with virtual bases" assert. Reduced repro coming up. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360580 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h11
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/AST/DeclCXX.cpp13
-rw-r--r--lib/AST/ExprConstant.cpp228
-rw-r--r--lib/Sema/SemaDeclCXX.cpp38
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp12
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp22
-rw-r--r--test/CXX/drs/dr18xx.cpp14
-rw-r--r--test/CXX/drs/dr6xx.cpp15
-rw-r--r--test/SemaCXX/constant-expression-cxx2a.cpp93
-rw-r--r--test/SemaCXX/cxx17-compat.cpp9
-rwxr-xr-xwww/cxx_status.html2
14 files changed, 52 insertions, 414 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index fc243de896..b8a4c1b1b7 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -2298,17 +2298,6 @@ public:
->getCorrespondingMethodInClass(RD, MayBeBase);
}
- /// Find if \p RD declares a function that overrides this function, and if so,
- /// return it. Does not search base classes.
- CXXMethodDecl *getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD,
- bool MayBeBase = false);
- const CXXMethodDecl *
- getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD,
- bool MayBeBase = false) const {
- return const_cast<CXXMethodDecl *>(this)
- ->getCorrespondingMethodDeclaredInClass(RD, MayBeBase);
- }
-
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 232987e95c..8801461a7e 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -32,8 +32,6 @@ def note_constexpr_no_return : Note<
"control reached end of constexpr function">;
def note_constexpr_virtual_call : Note<
"cannot evaluate call to virtual function in a constant expression">;
-def note_constexpr_pure_virtual_call : Note<
- "pure virtual function %q0 called">;
def note_constexpr_virtual_base : Note<
"cannot construct object of type %0 with virtual base class "
"in a constant expression">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 50832bd6bc..4cbaf2e1d3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2314,9 +2314,6 @@ def err_constexpr_redecl_mismatch : Error<
"%select{non-constexpr declaration of %0 follows constexpr declaration"
"|constexpr declaration of %0 follows non-constexpr declaration}1">;
def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
-def warn_cxx17_compat_constexpr_virtual : Warning<
- "virtual constexpr functions are incompatible with "
- "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
def err_constexpr_virtual_base : Error<
"constexpr %select{member function|constructor}0 not allowed in "
"%select{struct|interface|class}1 with virtual base "
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 51302a29b4..90002e9350 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5985,8 +5985,8 @@ public:
/// MarkVirtualMembersReferenced - Will mark all members of the given
/// CXXRecordDecl referenced.
- void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD,
- bool ConstexprOnly = false);
+ void MarkVirtualMembersReferenced(SourceLocation Loc,
+ const CXXRecordDecl *RD);
/// Define all of the vtables that have been used in this
/// translation unit and reference any virtual members used by those
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f9f70ecb59..b9ecdc6572 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1946,8 +1946,8 @@ static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
}
CXXMethodDecl *
-CXXMethodDecl::getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD,
- bool MayBeBase) {
+CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
+ bool MayBeBase) {
if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl())
return this;
@@ -1973,15 +1973,6 @@ CXXMethodDecl::getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD,
return MD;
}
- return nullptr;
-}
-
-CXXMethodDecl *
-CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
- bool MayBeBase) {
- if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase))
- return MD;
-
for (const auto &I : RD->bases()) {
const RecordType *RT = I.getType()->getAs<RecordType>();
if (!RT)
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index adc82bfe0b..ea36072bd9 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -37,7 +37,6 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
@@ -2486,21 +2485,6 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
return true;
}
-/// Cast an lvalue referring to a derived class to a known base subobject.
-static bool CastToBaseClass(EvalInfo &Info, const Expr *E, LValue &Result,
- const CXXRecordDecl *DerivedRD,
- const CXXRecordDecl *BaseRD) {
- CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/false);
- if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
- llvm_unreachable("Class must be derived from the passed in base class!");
-
- for (CXXBasePathElement &Elem : Paths.front())
- if (!HandleLValueBase(Info, E, Result, Elem.Class, Elem.Base))
- return false;
- return true;
-}
-
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
@@ -4477,19 +4461,16 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
}
// DR1872: An instantiated virtual constexpr function can't be called in a
- // constant expression (prior to C++20). We can still constant-fold such a
- // call.
- if (!Info.Ctx.getLangOpts().CPlusPlus2a && isa<CXXMethodDecl>(Declaration) &&
- cast<CXXMethodDecl>(Declaration)->isVirtual())
- Info.CCEDiag(CallLoc, diag::note_constexpr_virtual_call);
-
- if (Definition && Definition->isInvalidDecl()) {
- Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
+ // constant expression.
+ if (isa<CXXMethodDecl>(Declaration) &&
+ cast<CXXMethodDecl>(Declaration)->isVirtual()) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_virtual_call);
return false;
}
// Can we evaluate this function call?
- if (Definition && Definition->isConstexpr() && Body)
+ if (Definition && Definition->isConstexpr() &&
+ !Definition->isInvalidDecl() && Body)
return true;
if (Info.getLangOpts().CPlusPlus11) {
@@ -4565,153 +4546,6 @@ static bool checkMemberCallThisPointer(EvalInfo &Info, const Expr *E,
return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
}
-struct DynamicType {
- /// The dynamic class type of the object.
- const CXXRecordDecl *Type;
- /// The corresponding path length in the lvalue.
- unsigned PathLength;
-};
-
-static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
- unsigned PathLength) {
- assert(PathLength >= Designator.MostDerivedPathLength && PathLength <=
- Designator.Entries.size() && "invalid path length");
- return (PathLength == Designator.MostDerivedPathLength)
- ? Designator.MostDerivedType->getAsCXXRecordDecl()
- : getAsBaseClass(Designator.Entries[PathLength - 1]);
-}
-
-/// Determine the dynamic type of an object.
-static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, LValue &This) {
- // If we don't have an lvalue denoting an object of class type, there is no
- // meaningful dynamic type. (We consider objects of non-class type to have no
- // dynamic type.)
- if (This.Designator.IsOnePastTheEnd || This.Designator.Invalid ||
- !This.Designator.MostDerivedType->getAsCXXRecordDecl())
- return None;
-
- // FIXME: For very deep class hierarchies, it might be beneficial to use a
- // binary search here instead. But the overwhelmingly common case is that
- // we're not in the middle of a constructor, so it probably doesn't matter
- // in practice.
- ArrayRef<APValue::LValuePathEntry> Path = This.Designator.Entries;
- for (unsigned PathLength = This.Designator.MostDerivedPathLength;
- PathLength <= Path.size(); ++PathLength) {
- switch (Info.isEvaluatingConstructor(This.getLValueBase(),
- Path.slice(0, PathLength))) {
- case ConstructionPhase::Bases:
- // We're constructing a base class. This is not the dynamic type.
- break;
-
- case ConstructionPhase::None:
- case ConstructionPhase::AfterBases:
- // We've finished constructing the base classes, so this is the dynamic
- // type.
- return DynamicType{getBaseClassType(This.Designator, PathLength),
- PathLength};
- }
- }
-
- // CWG issue 1517: we're constructing a base class of the object described by
- // 'This', so that object has not yet begun its period of construction and
- // any polymorphic operation on it results in undefined behavior.
- return None;
-}
-
-/// Perform virtual dispatch.
-static const CXXMethodDecl *HandleVirtualDispatch(
- EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
- llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {
- Optional<DynamicType> DynType = ComputeDynamicType(Info, This);
- if (!DynType) {
- Info.FFDiag(E);
- return nullptr;
- }
-
- // Find the final overrider. It must be declared in one of the classes on the
- // path from the dynamic type to the static type.
- // FIXME: If we ever allow literal types to have virtual base classes, that
- // won't be true.
- const CXXMethodDecl *Callee = Found;
- unsigned PathLength = DynType->PathLength;
- for (/**/; PathLength <= This.Designator.Entries.size(); ++PathLength) {
- const CXXRecordDecl *Class = getBaseClassType(This.Designator, PathLength);
- assert(!Class->getNumVBases() &&
- "can't handle virtual calls with virtual bases");
-
- const CXXMethodDecl *Overrider =
- Found->getCorrespondingMethodDeclaredInClass(Class, false);
- if (Overrider) {
- Callee = Overrider;
- break;
- }
- }
-
- // C++2a [class.abstract]p6:
- // the effect of making a virtual call to a pure virtual function [...] is
- // undefined
- if (Callee->isPure()) {
- Info.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << Callee;
- Info.Note(Callee->getLocation(), diag::note_declared_at);
- return nullptr;
- }
-
- // If necessary, walk the rest of the path to determine the sequence of
- // covariant adjustment steps to apply.
- if (!Info.Ctx.hasSameUnqualifiedType(Callee->getReturnType(),
- Found->getReturnType())) {
- CovariantAdjustmentPath.push_back(Callee->getReturnType());
- for (unsigned CovariantPathLength = PathLength + 1;
- CovariantPathLength != This.Designator.Entries.size();
- ++CovariantPathLength) {
- const CXXRecordDecl *NextClass =
- getBaseClassType(This.Designator, CovariantPathLength);
- const CXXMethodDecl *Next =
- Found->getCorrespondingMethodDeclaredInClass(NextClass, false);
- if (Next && !Info.Ctx.hasSameUnqualifiedType(
- Next->getReturnType(), CovariantAdjustmentPath.back()))
- CovariantAdjustmentPath.push_back(Next->getReturnType());
- }
- if (!Info.Ctx.hasSameUnqualifiedType(Found->getReturnType(),
- CovariantAdjustmentPath.back()))
- CovariantAdjustmentPath.push_back(Found->getReturnType());
- }
-
- // Perform 'this' adjustment.
- if (!CastToDerivedClass(Info, E, This, Callee->getParent(), PathLength))
- return nullptr;
-
- return Callee;
-}
-
-/// Perform the adjustment from a value returned by a virtual function to
-/// a value of the statically expected type, which may be a pointer or
-/// reference to a base class of the returned type.
-static bool HandleCovariantReturnAdjustment(EvalInfo &Info, const Expr *E,
- APValue &Result,
- ArrayRef<QualType> Path) {
- assert(Result.isLValue() &&
- "unexpected kind of APValue for covariant return");
- if (Result.isNullPointer())
- return true;
-
- LValue LVal;
- LVal.setFrom(Info.Ctx, Result);
-
- const CXXRecordDecl *OldClass = Path[0]->getPointeeCXXRecordDecl();
- for (unsigned I = 1; I != Path.size(); ++I) {
- const CXXRecordDecl *NewClass = Path[I]->getPointeeCXXRecordDecl();
- assert(OldClass && NewClass && "unexpected kind of covariant return");
- if (OldClass != NewClass &&
- !CastToBaseClass(Info, E, LVal, OldClass, NewClass))
- return false;
- OldClass = NewClass;
- }
-
- LVal.moveInto(Result);
- return true;
-}
-
/// Determine if a class has any fields that might need to be copied by a
/// trivial copy or move operation.
static bool hasFields(const CXXRecordDecl *RD) {
@@ -4901,6 +4735,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
+
+ // This is the point at which the dynamic type of the object becomes this
+ // class type.
+ if (BasesSeen == RD->getNumBases())
+ EvalObj.finishedConstructingBases();
} else if ((FD = I->getMember())) {
if (!HandleLValueMember(Info, I->getInit(), Subobject, FD, &Layout))
return false;
@@ -4961,11 +4800,6 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
Success = false;
}
-
- // This is the point at which the dynamic type of the object becomes this
- // class type.
- if (I->isBaseInitializer() && BasesSeen == RD->getNumBases())
- EvalObj.finishedConstructingBases();
}
return Success &&
@@ -5206,30 +5040,27 @@ public:
const FunctionDecl *FD = nullptr;
LValue *This = nullptr, ThisVal;
auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
- bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
- const CXXMethodDecl *Member = nullptr;
+ const ValueDecl *Member = nullptr;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
// Explicit bound member calls, such as x.f() or p->g();
if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
return false;
- Member = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
- if (!Member)
- return Error(Callee);
+ Member = ME->getMemberDecl();
This = &ThisVal;
- HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
- Member = dyn_cast_or_null<CXXMethodDecl>(
- HandleMemberPointerAccess(Info, BE, ThisVal, false));
- if (!Member)
- return Error(Callee);
+ Member = HandleMemberPointerAccess(Info, BE, ThisVal, false);
+ if (!Member) return false;
This = &ThisVal;
} else
return Error(Callee);
- FD = Member;
+
+ FD = dyn_cast<FunctionDecl>(Member);
+ if (!FD)
+ return Error(Callee);
} else if (CalleeType->isFunctionPointerType()) {
LValue Call;
if (!EvaluatePointer(Callee, Call, Info))
@@ -5299,20 +5130,8 @@ public:
} else
return Error(E);
- SmallVector<QualType, 4> CovariantAdjustmentPath;
- if (This) {
- // Check that the 'this' pointer points to an object of the right type.
- if (!checkMemberCallThisPointer(Info, E, *This))
- return false;
-
- // Perform virtual dispatch, if necessary.
- auto *NamedMember = dyn_cast<CXXMethodDecl>(FD);
- if (NamedMember && NamedMember->isVirtual() && !HasQualifier) {
- if (!(FD = HandleVirtualDispatch(Info, E, *This, NamedMember,
- CovariantAdjustmentPath)))
- return true;
- }
- }
+ if (This && !checkMemberCallThisPointer(Info, E, *This))
+ return false;
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
@@ -5322,11 +5141,6 @@ public:
Result, ResultSlot))
return false;
- if (!CovariantAdjustmentPath.empty() &&
- !HandleCovariantReturnAdjustment(Info, E, Result,
- CovariantAdjustmentPath))
- return false;
-
return true;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1da2ca8ca5..afd50f1438 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1596,9 +1596,6 @@ 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)
@@ -1615,25 +1612,21 @@ 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; (removed in C++20)
+ // - it shall not be virtual;
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
- 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;
- }
+ 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;
@@ -15204,8 +15197,7 @@ void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
}
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
- const CXXRecordDecl *RD,
- bool ConstexprOnly) {
+ const CXXRecordDecl *RD) {
// Mark all functions which will appear in RD's vtable as used.
CXXFinalOverriderMap FinalOverriders;
RD->getFinalOverriders(FinalOverriders);
@@ -15220,7 +15212,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() && (!ConstexprOnly || Overrider->isConstexpr()))
+ if (!Overrider->isPure())
MarkFunctionReferenced(Loc, Overrider);
}
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 55d1d94bd8..edc281cad6 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2082,7 +2082,6 @@ 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:
@@ -2129,10 +2128,6 @@ 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())
@@ -2225,14 +2220,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Consumer.HandleTagDeclDefinition(Instantiation);
// Always emit the vtable for an explicit instantiation definition
- // of a polymorphic class template specialization. Otherwise, eagerly
- // instantiate only constexpr virtual functions in preparation for their use
- // in constant evaluation.
+ // of a polymorphic class template specialization.
if (TSK == TSK_ExplicitInstantiationDefinition)
MarkVTableUsed(PointOfInstantiation, Instantiation, true);
- else if (MightHaveConstexprVirtualFunctions)
- MarkVirtualMembersReferenced(PointOfInstantiation, Instantiation,
- /*ConstexprOnly*/ true);
}
return Instantiation->isInvalidDecl();
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index cc3917093e..ffc408cddb 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -20,10 +20,7 @@ struct Literal {
};
struct S {
- virtual int ImplicitlyVirtual() const = 0;
-#if __cplusplus <= 201703L
- // expected-note@-2 {{overridden virtual function}}
-#endif
+ virtual int ImplicitlyVirtual() const = 0; // expected-note {{overridden virtual function}}
};
struct SS : S {
int ImplicitlyVirtual() const;
@@ -35,21 +32,12 @@ struct T : SS, NonLiteral {
constexpr T();
constexpr int f() const;
- // - it shall not be virtual; [until C++20]
- virtual constexpr int ExplicitlyVirtual() const { return 0; }
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#endif
+ // - it shall not be virtual;
+ virtual constexpr int ExplicitlyVirtual() const { return 0; } // expected-error {{virtual function cannot be constexpr}}
- constexpr int ImplicitlyVirtual() const { return 0; }
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#endif
+ constexpr int ImplicitlyVirtual() const { return 0; } // expected-error {{virtual function cannot be constexpr}}
- virtual constexpr int OutOfLineVirtual() const;
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#endif
+ virtual constexpr int OutOfLineVirtual() const; // expected-error {{virtual function cannot be constexpr}}
// - its return type shall be a literal type;
constexpr NonLiteral NonLiteralReturn() const { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
diff --git a/test/CXX/drs/dr18xx.cpp b/test/CXX/drs/dr18xx.cpp
index 33c0452b6c..5df132c368 100644
--- a/test/CXX/drs/dr18xx.cpp
+++ b/test/CXX/drs/dr18xx.cpp
@@ -52,19 +52,9 @@ namespace dr1872 { // dr1872: 9
struct Z : virtual X {};
constexpr int x = A<X>().f();
- constexpr int y = A<Y>().f();
-#if __cplusplus <= 201703L
- // expected-error@-2 {{constant expression}} expected-note@-2 {{call to virtual function}}
-#else
- static_assert(y == 0);
-#endif
+ constexpr int y = A<Y>().f(); // expected-error {{constant expression}} expected-note {{call to virtual function}}
// Note, this is invalid even though it would not use virtual dispatch.
- constexpr int y2 = A<Y>().A<Y>::f();
-#if __cplusplus <= 201703L
- // expected-error@-2 {{constant expression}} expected-note@-2 {{call to virtual function}}
-#else
- static_assert(y == 0);
-#endif
+ constexpr int y2 = A<Y>().A<Y>::f(); // expected-error {{constant expression}} expected-note {{call to virtual function}}
constexpr int z = A<Z>().f(); // expected-error {{constant expression}} expected-note {{non-literal type}}
#endif
}
diff --git a/test/CXX/drs/dr6xx.cpp b/test/CXX/drs/dr6xx.cpp
index 31642dfbb0..318096c299 100644
--- a/test/CXX/drs/dr6xx.cpp
+++ b/test/CXX/drs/dr6xx.cpp
@@ -479,21 +479,12 @@ namespace dr647 { // dr647: yes
// This is partially superseded by dr1358.
struct A {
constexpr virtual void f() const;
- constexpr virtual void g() const {}
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#endif
+ constexpr virtual void g() const {} // expected-error {{virtual function cannot be constexpr}}
};
- struct X { virtual void f() const; };
-#if __cplusplus <= 201703L
- // expected-note@-2 {{overridden}}
-#endif
+ struct X { virtual void f() const; }; // expected-note {{overridden}}
struct B : X {
- constexpr void f() const {}
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#endif
+ constexpr void f() const {} // expected-error {{virtual function cannot be constexpr}}
};
struct NonLiteral { NonLiteral() {} }; // expected-note {{not an aggregate and has no constexpr constructors}}
diff --git a/test/SemaCXX/constant-expression-cxx2a.cpp b/test/SemaCXX/constant-expression-cxx2a.cpp
index c41c1d0481..bb2a4a07dd 100644
--- a/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -211,96 +211,3 @@ constexpr bool for_range_init() {
return k == 6;
}
static_assert(for_range_init());
-
-namespace Virtual {
- struct NonZeroOffset { int padding = 123; };
-
- // Ensure that we pick the right final overrider during construction.
- struct A {
- virtual constexpr char f() const { return 'A'; }
- char a = f();
- };
- struct NoOverrideA : A {};
- struct B : NonZeroOffset, NoOverrideA {
- virtual constexpr char f() const { return 'B'; }
- char b = f();
- };
- struct NoOverrideB : B {};
- struct C : NonZeroOffset, A {
- virtual constexpr char f() const { return 'C'; }
- A *pba;
- char c = ((A*)this)->f();
- char ba = pba->f();
- constexpr C(A *pba) : pba(pba) {}
- };
- struct D : NonZeroOffset, NoOverrideB, C { // expected-warning {{inaccessible}}
- virtual constexpr char f() const { return 'D'; }
- char d = f();
- constexpr D() : C((B*)this) {}
- };
- constexpr D d;
- static_assert(((B&)d).a == 'A');
- static_assert(((C&)d).a == 'A');
- static_assert(d.b == 'B');
- static_assert(d.c == 'C');
- // During the construction of C, the dynamic type of B's A is B.
- static_assert(d.ba == 'B');
- static_assert(d.d == 'D');
- static_assert(d.f() == 'D');
- constexpr const A &a = (B&)d;
- constexpr const B &b = d;
- static_assert(a.f() == 'D');
- static_assert(b.f() == 'D');
-
- // FIXME: It is unclear whether this should be permitted. We assume that
- // objects whose values are not known within evaluation are within their
- // lifetimes.
- D d_not_constexpr;
- static_assert(d_not_constexpr.f() == 'D');
-
- // Check that we apply a proper adjustment for a covariant return type.
- struct Covariant1 {
- D d;
- virtual const A *f() const;
- };
- template<typename T>
- struct Covariant2 : Covariant1 {
- virtual const T *f() const;
- };
- template<typename T>
- struct Covariant3 : Covariant2<T> {
- constexpr virtual const D *f() const { return &this->d; }
- };
-
- constexpr Covariant3<B> cb;
- constexpr Covariant3<C> cc;
-
- constexpr const Covariant1 *cb1 = &cb;
- constexpr const Covariant2<B> *cb2 = &cb;
- static_assert(cb1->f()->a == 'A');
- static_assert(cb1->f() == (B*)&cb.d);
- static_assert(cb1->f()->f() == 'D');
- static_assert(cb2->f()->b == 'B');
- static_assert(cb2->f() == &cb.d);
- static_assert(cb2->f()->f() == 'D');
-
- constexpr const Covariant1 *cc1 = &cc;
- constexpr const Covariant2<C> *cc2 = &cc;
- static_assert(cc1->f()->a == 'A');
- static_assert(cc1->f() == (C*)&cc.d);
- static_assert(cc1->f()->f() == 'D');
- static_assert(cc2->f()->c == 'C');
- static_assert(cc2->f() == &cc.d);
- static_assert(cc2->f()->f() == 'D');
-
- static_assert(cb.f()->d == 'D');
- static_assert(cc.f()->d == 'D');
-
- struct Abstract {
- constexpr virtual void f() = 0; // expected-note {{declared here}}
- constexpr Abstract() { do_it(); } // expected-note {{in call to}}
- constexpr void do_it() { f(); } // expected-note {{pure virtual function 'Virtual::Abstract::f' called}}
- };
- struct PureVirtualCall : Abstract { void f(); }; // expected-note {{in call to 'Abstract}}
- constexpr PureVirtualCall pure_virtual_call; // expected-error {{constant expression}} expected-note {{in call to 'PureVirtualCall}}
-}
diff --git a/test/SemaCXX/cxx17-compat.cpp b/test/SemaCXX/cxx17-compat.cpp
index 5fcec2ab9c..eee9c239d1 100644
--- a/test/SemaCXX/cxx17-compat.cpp
+++ b/test/SemaCXX/cxx17-compat.cpp
@@ -63,12 +63,3 @@ void ForRangeInit() {
// expected-warning@-4 {{range-based for loop initialization statements are incompatible with C++ standards before C++2a}}
#endif
}
-
-struct ConstexprVirtual {
- virtual constexpr void f() {}
-#if __cplusplus <= 201703L
- // expected-error@-2 {{virtual function cannot be constexpr}}
-#else
- // expected-warning@-4 {{virtual constexpr functions are incompatible with C++ standards before C++2a}}
-#endif
-};
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 84552c2018..5a3cc4fdc1 100755
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -965,7 +965,7 @@ as the draft C++2a standard evolves.
<tr>
<td rowspan=4>Relaxations of <tt>constexpr</tt> restrictions</td>
<td><a href="http://wg21.link/p1064r0">P1064R0</a></td>
- <td class="svn" align="center">SVN</td>
+ <td class="none" align="center">No</td>
</tr>
<tr> <!-- from San Diego -->
<td><a href="http://wg21.link/p1002r1">P1002R1</a></td>