r360580 - Revert r360559 "[c++20] P1064R0: Allow virtual function calls in constant expression evaluation."

Hans Wennborg via cfe-commits cfe-commits at lists.llvm.org
Mon May 13 06:19:10 PDT 2019


Author: hans
Date: Mon May 13 06:19:09 2019
New Revision: 360580

URL: http://llvm.org/viewvc/llvm-project?rev=360580&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
    cfe/trunk/test/CXX/drs/dr18xx.cpp
    cfe/trunk/test/CXX/drs/dr6xx.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
    cfe/trunk/test/SemaCXX/cxx17-compat.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon May 13 06:19:09 2019
@@ -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) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Mon May 13 06:19:09 2019
@@ -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">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May 13 06:19:09 2019
@@ -2314,9 +2314,6 @@ def err_constexpr_redecl_mismatch : Erro
   "%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 "

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon May 13 06:19:09 2019
@@ -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

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon May 13 06:19:09 2019
@@ -1946,8 +1946,8 @@ static bool recursivelyOverrides(const C
 }
 
 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::getCorrespondingMethodDec
       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)

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon May 13 06:19:09 2019
@@ -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(EvalInf
   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(EvalI
   }
 
   // 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(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
                                   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
         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;
   }
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon May 13 06:19:09 2019
@@ -1596,9 +1596,6 @@ bool Sema::CheckConstexprFunctionDecl(co
     //  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(co
     // 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);
+      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 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::MarkVirtualMemberExceptionSpe
 }
 
 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(
 
       // 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);
     }
   }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon May 13 06:19:09 2019
@@ -2082,7 +2082,6 @@ Sema::InstantiateClass(SourceLocation Po
   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 Po
           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 Po
     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();

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Mon May 13 06:19:09 2019
@@ -20,10 +20,7 @@ struct Literal {
 };
 
 struct S {
-  virtual int ImplicitlyVirtual() const = 0;
-#if __cplusplus <= 201703L
-  // expected-note at -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 at -2 {{virtual function cannot be constexpr}}
-#endif
-
-  constexpr int ImplicitlyVirtual() const { return 0; }
-#if __cplusplus <= 201703L
-  // expected-error at -2 {{virtual function cannot be constexpr}}
-#endif
-
-  virtual constexpr int OutOfLineVirtual() const;
-#if __cplusplus <= 201703L
-  // expected-error at -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; } // expected-error {{virtual function cannot be constexpr}}
+
+  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}}

Modified: cfe/trunk/test/CXX/drs/dr18xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr18xx.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr18xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr18xx.cpp Mon May 13 06:19:09 2019
@@ -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 at -2 {{constant expression}} expected-note at -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 at -2 {{constant expression}} expected-note at -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
 }

Modified: cfe/trunk/test/CXX/drs/dr6xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr6xx.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr6xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr6xx.cpp Mon May 13 06:19:09 2019
@@ -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 at -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 at -2 {{overridden}}
-#endif
+  struct X { virtual void f() const; }; // expected-note {{overridden}}
   struct B : X {
-    constexpr void f() const {}
-#if __cplusplus <= 201703L
-    // expected-error at -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}}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp Mon May 13 06:19:09 2019
@@ -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}}
-}

Modified: cfe/trunk/test/SemaCXX/cxx17-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx17-compat.cpp?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx17-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx17-compat.cpp Mon May 13 06:19:09 2019
@@ -63,12 +63,3 @@ void ForRangeInit() {
     // expected-warning at -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 at -2 {{virtual function cannot be constexpr}}
-#else
-    // expected-warning at -4 {{virtual constexpr functions are incompatible with C++ standards before C++2a}}
-#endif
-};

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=360580&r1=360579&r2=360580&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Mon May 13 06:19:09 2019
@@ -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>




More information about the cfe-commits mailing list