[clang] 8f8b9f2 - PR47805: Use a single object for a function parameter in the caller and

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 13 18:51:00 PDT 2020


Author: Richard Smith
Date: 2020-10-13T18:50:46-07:00
New Revision: 8f8b9f2cca0b73314342c721186ae9c860ca273c

URL: https://github.com/llvm/llvm-project/commit/8f8b9f2cca0b73314342c721186ae9c860ca273c
DIFF: https://github.com/llvm/llvm-project/commit/8f8b9f2cca0b73314342c721186ae9c860ca273c.diff

LOG: PR47805: Use a single object for a function parameter in the caller and
callee in constant evaluation.

We previously made a deep copy of function parameters of class type when
passing them, resulting in the destructor for the parameter applying to
the original argument value, ignoring any modifications made in the
function body. This also meant that the 'this' pointer of the function
parameter could be observed changing between the caller and the callee.

This change completely reimplements how we model function parameters
during constant evaluation. We now model them roughly as if they were
variables living in the caller, albeit with an artificially reduced
scope that covers only the duration of the function call, instead of
modeling them as temporaries in the caller that we partially "reparent"
into the callee at the point of the call. This brings some minor
diagnostic improvements, as well as significantly reduced stack usage
during constant evaluation.

Added: 
    

Modified: 
    clang/lib/AST/ExprConstant.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
    clang/test/CXX/except/except.spec/p1.cpp
    clang/test/CXX/expr/expr.const/p2-0x.cpp
    clang/test/OpenMP/critical_messages.cpp
    clang/test/OpenMP/distribute_parallel_for_simd_safelen_messages.cpp
    clang/test/OpenMP/distribute_simd_safelen_messages.cpp
    clang/test/OpenMP/distribute_simd_simdlen_messages.cpp
    clang/test/OpenMP/target_teams_distribute_parallel_for_simd_safelen_messages.cpp
    clang/test/OpenMP/target_teams_distribute_parallel_for_simd_simdlen_messages.cpp
    clang/test/OpenMP/target_teams_distribute_simd_safelen_messages.cpp
    clang/test/OpenMP/target_teams_distribute_simd_simdlen_messages.cpp
    clang/test/OpenMP/teams_distribute_parallel_for_simd_safelen_messages.cpp
    clang/test/OpenMP/teams_distribute_parallel_for_simd_simdlen_messages.cpp
    clang/test/OpenMP/teams_distribute_simd_safelen_messages.cpp
    clang/test/OpenMP/teams_distribute_simd_simdlen_messages.cpp
    clang/test/Sema/builtin-expect-with-probability-avr.cpp
    clang/test/Sema/builtin-expect-with-probability.cpp
    clang/test/Sema/c89.c
    clang/test/SemaCUDA/constexpr-variables.cu
    clang/test/SemaCXX/c99-variable-length-array-cxx11.cpp
    clang/test/SemaCXX/c99-variable-length-array.cpp
    clang/test/SemaCXX/constant-expression-cxx11.cpp
    clang/test/SemaCXX/constant-expression-cxx2a.cpp
    clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
    clang/test/SemaCXX/cxx2a-consteval.cpp
    clang/test/SemaCXX/integer-overflow.cpp
    clang/test/SemaCXX/vla-construct.cpp
    clang/test/SemaCXX/warn-vla.cpp
    clang/test/SemaTemplate/typo-dependent-name.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1327aa6876e4..74ec7040564f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -490,6 +490,39 @@ namespace {
     }
   };
 
+  /// A scope at the end of which an object can need to be destroyed.
+  enum class ScopeKind {
+    Block,
+    FullExpression,
+    Call
+  };
+
+  /// A reference to a particular call and its arguments.
+  struct CallRef {
+    CallRef() : OrigCallee(), CallIndex(0), Version() {}
+    CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
+        : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
+
+    explicit operator bool() const { return OrigCallee; }
+
+    /// Get the parameter that the caller initialized, corresponding to the
+    /// given parameter in the callee.
+    const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
+      return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
+                        : PVD;
+    }
+
+    /// The callee at the point where the arguments were evaluated. This might
+    /// be 
diff erent from the actual callee (a 
diff erent redeclaration, or a
+    /// virtual override), but this function's parameters are the ones that
+    /// appear in the parameter map.
+    const FunctionDecl *OrigCallee;
+    /// The call index of the frame that holds the argument values.
+    unsigned CallIndex;
+    /// The version of the parameters corresponding to this call.
+    unsigned Version;
+  };
+
   /// A stack frame in the constexpr call stack.
   class CallStackFrame : public interp::Frame {
   public:
@@ -504,9 +537,10 @@ namespace {
     /// This - The binding for the this pointer in this call, if any.
     const LValue *This;
 
-    /// Arguments - Parameter bindings for this function call, indexed by
-    /// parameters' function scope indices.
-    APValue *Arguments;
+    /// Information on how to find the arguments to this call. Our arguments
+    /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
+    /// key and this value as the version.
+    CallRef Arguments;
 
     /// Source location information about the default argument or default
     /// initializer expression we're evaluating, if any.
@@ -539,6 +573,10 @@ namespace {
       TempVersionStack.pop_back();
     }
 
+    CallRef createCall(const FunctionDecl *Callee) {
+      return {Callee, Index, ++CurTempVersion};
+    }
+
     // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
     // on the overall stack usage of deeply-recursing constexpr evaluations.
     // (We should cache this map rather than recomputing it repeatedly.)
@@ -552,7 +590,7 @@ namespace {
 
     CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
                    const FunctionDecl *Callee, const LValue *This,
-                   APValue *Arguments);
+                   CallRef Arguments);
     ~CallStackFrame();
 
     // Return the temporary for Key whose version number is Version.
@@ -591,7 +629,10 @@ namespace {
     /// bumping the temporary version number.
     template<typename KeyT>
     APValue &createTemporary(const KeyT *Key, QualType T,
-                             bool IsLifetimeExtended, LValue &LV);
+                             ScopeKind Scope, LValue &LV);
+
+    /// Allocate storage for a parameter of a function call made in this frame.
+    APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
 
     void describe(llvm::raw_ostream &OS) override;
 
@@ -605,6 +646,10 @@ namespace {
           return true;
       return false;
     }
+
+  private:
+    APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
+                         ScopeKind Scope);
   };
 
   /// Temporarily override 'this'.
@@ -633,16 +678,20 @@ static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
 namespace {
   /// A cleanup, and a flag indicating whether it is lifetime-extended.
   class Cleanup {
-    llvm::PointerIntPair<APValue*, 1, bool> Value;
+    llvm::PointerIntPair<APValue*, 2, ScopeKind> Value;
     APValue::LValueBase Base;
     QualType T;
 
   public:
     Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
-            bool IsLifetimeExtended)
-        : Value(Val, IsLifetimeExtended), Base(Base), T(T) {}
+            ScopeKind Scope)
+        : Value(Val, Scope), Base(Base), T(T) {}
 
-    bool isLifetimeExtended() const { return Value.getInt(); }
+    /// Determine whether this cleanup should be performed at the end of the
+    /// given kind of scope.
+    bool isDestroyedAtEndOf(ScopeKind K) const {
+      return (int)Value.getInt() >= (int)K;
+    }
     bool endLifetime(EvalInfo &Info, bool RunDestructors) {
       if (RunDestructors) {
         SourceLocation Loc;
@@ -928,7 +977,7 @@ namespace {
           CallStackDepth(0), NextCallIndex(1),
           StepsLeft(C.getLangOpts().ConstexprStepLimit),
           EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
-          BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
+          BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()),
           EvaluatingDecl((const ValueDecl *)nullptr),
           EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
           HasFoldFailureDiagnostic(false), InConstantContext(false),
@@ -997,6 +1046,13 @@ namespace {
       return Result;
     }
 
+    /// Get the allocated storage for the given parameter of the given call.
+    APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
+      CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
+      return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
+                   : nullptr;
+    }
+
     /// Information about a stack frame for std::allocator<T>::[de]allocate.
     struct StdAllocatorCaller {
       unsigned FrameIndex;
@@ -1032,10 +1088,13 @@ namespace {
 
     void performLifetimeExtension() {
       // Disable the cleanups for lifetime-extended temporaries.
-      CleanupStack.erase(
-          std::remove_if(CleanupStack.begin(), CleanupStack.end(),
-                         [](Cleanup &C) { return C.isLifetimeExtended(); }),
-          CleanupStack.end());
+      CleanupStack.erase(std::remove_if(CleanupStack.begin(),
+                                        CleanupStack.end(),
+                                        [](Cleanup &C) {
+                                          return !C.isDestroyedAtEndOf(
+                                              ScopeKind::FullExpression);
+                                        }),
+                         CleanupStack.end());
      }
 
     /// Throw away any remaining cleanups at the end of evaluation. If any
@@ -1284,7 +1343,7 @@ namespace {
 
   /// RAII object wrapping a full-expression or block scope, and handling
   /// the ending of the lifetime of temporaries created within it.
-  template<bool IsFullExpression>
+  template<ScopeKind Kind>
   class ScopeRAII {
     EvalInfo &Info;
     unsigned OldStackSize;
@@ -1317,8 +1376,7 @@ namespace {
       // for a full-expression scope.
       bool Success = true;
       for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
-        if (!(IsFullExpression &&
-              Info.CleanupStack[I - 1].isLifetimeExtended())) {
+        if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
           if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
             Success = false;
             break;
@@ -1326,18 +1384,20 @@ namespace {
         }
       }
 
-      // Compact lifetime-extended cleanups.
+      // Compact any retained cleanups.
       auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
-      if (IsFullExpression)
+      if (Kind != ScopeKind::Block)
         NewEnd =
-            std::remove_if(NewEnd, Info.CleanupStack.end(),
-                           [](Cleanup &C) { return !C.isLifetimeExtended(); });
+            std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
+              return C.isDestroyedAtEndOf(Kind);
+            });
       Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
       return Success;
     }
   };
-  typedef ScopeRAII<false> BlockScopeRAII;
-  typedef ScopeRAII<true> FullExpressionRAII;
+  typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
+  typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
+  typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
 }
 
 bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
@@ -1380,9 +1440,9 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
 
 CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
                                const FunctionDecl *Callee, const LValue *This,
-                               APValue *Arguments)
+                               CallRef Call)
     : Info(Info), Caller(Info.CurrentCall), Callee(Callee), This(This),
-      Arguments(Arguments), CallLoc(CallLoc), Index(Info.NextCallIndex++) {
+      Arguments(Call), CallLoc(CallLoc), Index(Info.NextCallIndex++) {
   Info.CurrentCall = this;
   ++Info.CallStackDepth;
 }
@@ -1795,14 +1855,33 @@ static void negateAsSigned(APSInt &Int) {
 
 template<typename KeyT>
 APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
-                                         bool IsLifetimeExtended, LValue &LV) {
+                                         ScopeKind Scope, LValue &LV) {
   unsigned Version = getTempVersion();
   APValue::LValueBase Base(Key, Index, Version);
   LV.set(Base);
+  return createLocal(Base, Key, T, Scope);
+}
+
+/// Allocate storage for a parameter of a function call made in this frame.
+APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD,
+                                     LValue &LV) {
+  assert(Args.CallIndex == Index && "creating parameter in wrong frame");
+  APValue::LValueBase Base(PVD, Index, Args.Version);
+  LV.set(Base);
+  // We always destroy parameters at the end of the call, even if we'd allow
+  // them to live to the end of the full-expression at runtime, in order to
+  // give portable results and match other compilers.
+  return createLocal(Base, PVD, PVD->getType(), ScopeKind::Call);
+}
+
+APValue &CallStackFrame::createLocal(APValue::LValueBase Base, const void *Key,
+                                     QualType T, ScopeKind Scope) {
+  assert(Base.getCallIndex() == Index && "lvalue for wrong frame");
+  unsigned Version = Base.getVersion();
   APValue &Result = Temporaries[MapKeyTy(Key, Version)];
-  assert(Result.isAbsent() && "temporary created multiple times");
+  assert(Result.isAbsent() && "local created multiple times");
 
-  // If we're creating a temporary immediately in the operand of a speculative
+  // If we're creating a local immediately in the operand of a speculative
   // evaluation, don't register a cleanup to be run outside the speculative
   // evaluation context, since we won't actually be able to initialize this
   // object.
@@ -1810,7 +1889,7 @@ APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
     if (T.isDestructedType())
       Info.noteSideEffect();
   } else {
-    Info.CleanupStack.push_back(Cleanup(&Result, Base, T, IsLifetimeExtended));
+    Info.CleanupStack.push_back(Cleanup(&Result, Base, T, Scope));
   }
   return Result;
 }
@@ -1856,12 +1935,11 @@ void CallStackFrame::describe(raw_ostream &Out) {
       Out << ", ";
 
     const ParmVarDecl *Param = *I;
-    if (Arguments) {
-      const APValue &Arg = Arguments[ArgIndex];
-      Arg.printPretty(Out, Info.Ctx, Param->getType());
-    } else {
+    APValue *V = Info.getParamSlot(Arguments, Param);
+    if (V)
+      V->printPretty(Out, Info.Ctx, Param->getType());
+    else
       Out << "<...>";
-    }
 
     if (ArgIndex == 0 && IsMemberCall)
       Out << "->" << *Callee << '(';
@@ -1992,6 +2070,22 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
 static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
   assert(Base && "no location for a null lvalue");
   const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+
+  // For a parameter, find the corresponding call stack frame (if it still
+  // exists), and point at the parameter of the function definition we actually
+  // invoked.
+  if (auto *PVD = dyn_cast_or_null<ParmVarDecl>(VD)) {
+    unsigned Idx = PVD->getFunctionScopeIndex();
+    for (CallStackFrame *F = Info.CurrentCall; F; F = F->Caller) {
+      if (F->Arguments.CallIndex == Base.getCallIndex() &&
+          F->Arguments.Version == Base.getVersion() && F->Callee &&
+          Idx < F->Callee->getNumParams()) {
+        VD = F->Callee->getParamDecl(Idx);
+        break;
+      }
+    }
+  }
+
   if (VD)
     Info.Note(VD->getLocation(), diag::note_declared_at);
   else if (const Expr *E = Base.dyn_cast<const Expr*>())
@@ -3077,33 +3171,22 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
 /// \param Info   Information about the ongoing evaluation.
 /// \param E      An expression to be used when printing diagnostics.
 /// \param VD     The variable whose initializer should be obtained.
+/// \param Version The version of the variable within the frame.
 /// \param Frame  The frame in which the variable was created. Must be null
 ///               if this variable is not local to the evaluation.
 /// \param Result Filled in with a pointer to the value of the variable.
 static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
                                 const VarDecl *VD, CallStackFrame *Frame,
-                                APValue *&Result, const LValue *LVal) {
-
-  // If this is a parameter to an active constexpr function call, perform
-  // argument substitution.
-  if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
-    // Assume arguments of a potential constant expression are unknown
-    // constant expressions.
-    if (Info.checkingPotentialConstantExpression())
-      return false;
-    if (!Frame || !Frame->Arguments) {
-      Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << VD;
-      return false;
-    }
-    Result = &Frame->Arguments[PVD->getFunctionScopeIndex()];
-    return true;
-  }
+                                unsigned Version, APValue *&Result) {
+  APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version);
 
   // If this is a local variable, dig out its value.
   if (Frame) {
-    Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion())
-                  : Frame->getCurrentTemporary(VD);
-    if (!Result) {
+    Result = Frame->getTemporary(VD, Version);
+    if (Result)
+      return true;
+
+    if (!isa<ParmVarDecl>(VD)) {
       // Assume variables referenced within a lambda's call operator that were
       // not declared within the call operator are captures and during checking
       // of a potential constant expression, assume they are unknown constant
@@ -3113,13 +3196,30 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
              "missing value for local variable");
       if (Info.checkingPotentialConstantExpression())
         return false;
-      // FIXME: implement capture evaluation during constant expr evaluation.
+      // FIXME: This diagnostic is bogus; we do support captures. Is this code
+      // still reachable at all?
       Info.FFDiag(E->getBeginLoc(),
                   diag::note_unimplemented_constexpr_lambda_feature_ast)
           << "captures not currently allowed";
       return false;
     }
-    return true;
+  }
+
+  if (isa<ParmVarDecl>(VD)) {
+    // Assume parameters of a potential constant expression are usable in
+    // constant expressions.
+    if (!Info.checkingPotentialConstantExpression() ||
+        !Info.CurrentCall->Callee ||
+        !Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
+      if (Info.getLangOpts().CPlusPlus11) {
+        Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown)
+            << VD;
+        NoteLValueLocation(Info, Base);
+      } else {
+        Info.FFDiag(E);
+      }
+    }
+    return false;
   }
 
   // Dig out the initializer, and use the declaration which it's attached to.
@@ -3132,7 +3232,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
     if (!Info.checkingPotentialConstantExpression()) {
       Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
         << VD;
-      Info.Note(VD->getLocation(), diag::note_declared_at);
+      NoteLValueLocation(Info, Base);
     }
     return false;
   }
@@ -3149,7 +3249,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
                          ? diag::note_constexpr_ltor_non_constexpr
                          : diag::note_constexpr_ltor_non_integral, 1)
           << VD << VD->getType();
-      Info.Note(VD->getLocation(), diag::note_declared_at);
+      NoteLValueLocation(Info, Base);
     }
     return false;
   }
@@ -3168,7 +3268,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
   if (!VD->evaluateValue(Notes)) {
     Info.FFDiag(E, diag::note_constexpr_var_init_non_constant,
               Notes.size() + 1) << VD;
-    Info.Note(VD->getLocation(), diag::note_declared_at);
+    NoteLValueLocation(Info, Base);
     Info.addNotes(Notes);
     return false;
   }
@@ -3177,7 +3277,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
   if (!VD->checkInitIsICE()) {
     Info.CCEDiag(E, diag::note_constexpr_var_init_non_constant,
                  Notes.size() + 1) << VD;
-    Info.Note(VD->getLocation(), diag::note_declared_at);
+    NoteLValueLocation(Info, Base);
     Info.addNotes(Notes);
   }
 
@@ -3185,7 +3285,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
   // folding. We can't be sure that this is the definition that will be used.
   if (VD->isWeak()) {
     Info.FFDiag(E, diag::note_constexpr_var_init_weak) << VD;
-    Info.Note(VD->getLocation(), diag::note_declared_at);
+    NoteLValueLocation(Info, Base);
     return false;
   }
 
@@ -3899,8 +3999,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
     // Unless we're looking at a local variable or argument in a constexpr call,
     // the variable we're reading must be const.
     if (!Frame) {
-      if (Info.getLangOpts().CPlusPlus14 &&
-          lifetimeStartedInEvaluation(Info, LVal.Base)) {
+      if (isa<ParmVarDecl>(VD)) {
+        // Allow evaluateVarDeclInit to diagnose this (or permit it during
+        // potential constant expression checking).
+      } else if (Info.getLangOpts().CPlusPlus14 &&
+                 lifetimeStartedInEvaluation(Info, LVal.Base)) {
         // OK, we can read and modify an object if we're in the process of
         // evaluating its initializer, because its lifetime began in this
         // evaluation.
@@ -3957,7 +4060,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
       }
     }
 
-    if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal))
+    if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
       return CompleteObject();
   } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
     Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
@@ -4026,13 +4129,19 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
   }
 
   // In C++14, we can't safely access any mutable state when we might be
-  // evaluating after an unmodeled side effect.
+  // evaluating after an unmodeled side effect. Parameters are modeled as state
+  // in the caller, but aren't visible once the call returns, so they can be
+  // modified in a speculatively-evaluated call.
   //
   // FIXME: Not all local state is mutable. Allow local constant subobjects
   // to be read here (but take care with 'mutable' fields).
+  unsigned VisibleDepth = Depth;
+  if (llvm::isa_and_nonnull<ParmVarDecl>(
+          LVal.Base.dyn_cast<const ValueDecl *>()))
+    ++VisibleDepth;
   if ((Frame && Info.getLangOpts().CPlusPlus14 &&
        Info.EvalStatus.HasSideEffects) ||
-      (isModification(AK) && Depth < Info.SpeculativeEvaluationDepth))
+      (isModification(AK) && VisibleDepth < Info.SpeculativeEvaluationDepth))
     return CompleteObject();
 
   return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType);
@@ -4643,8 +4752,8 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
     return true;
 
   LValue Result;
-  APValue &Val =
-      Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result);
+  APValue &Val = Info.CurrentCall->createTemporary(VD, VD->getType(),
+                                                   ScopeKind::Block, Result);
 
   const Expr *InitE = VD->getInit();
   if (!InitE)
@@ -5789,15 +5898,35 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
   return true;
 }
 
-namespace {
-typedef SmallVector<APValue, 8> ArgVector;
-}
+static bool EvaluateCallArg(const ParmVarDecl *PVD, const Expr *Arg,
+                            CallRef Call, EvalInfo &Info,
+                            bool NonNull = false) {
+  LValue LV;
+  // Create the parameter slot and register its destruction. For a vararg
+  // argument, create a temporary.
+  // FIXME: For calling conventions that destroy parameters in the callee,
+  // should we consider performing destruction when the function returns
+  // instead?
+  APValue &V = PVD ? Info.CurrentCall->createParam(Call, PVD, LV)
+                   : Info.CurrentCall->createTemporary(Arg, Arg->getType(),
+                                                       ScopeKind::Call, LV);
+  if (!EvaluateInPlace(V, Info, LV, Arg))
+    return false;
 
-/// EvaluateArgs - Evaluate the arguments to a function call.
-static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
-                         EvalInfo &Info, const FunctionDecl *Callee) {
-  ArgValues.resize(Args.size());
+  // Passing a null pointer to an __attribute__((nonnull)) parameter results in
+  // undefined behavior, so is non-constant.
+  if (NonNull && V.isLValue() && V.isNullPointer()) {
+    Info.CCEDiag(Arg, diag::note_non_null_attribute_failed);
+    return false;
+  }
+
+  return true;
+}
 
+/// Evaluate the arguments to a function call.
+static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
+                         EvalInfo &Info, const FunctionDecl *Callee,
+                         bool RightToLeft = false) {
   bool Success = true;
   llvm::SmallBitVector ForbiddenNullArgs;
   if (Callee->hasAttr<NonNullAttr>()) {
@@ -5815,36 +5944,53 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
         }
     }
   }
-  for (unsigned Idx = 0; Idx < Args.size(); Idx++) {
-    if (!Evaluate(ArgValues[Idx], Info, Args[Idx])) {
+  for (unsigned I = 0; I < Args.size(); I++) {
+    unsigned Idx = RightToLeft ? Args.size() - I - 1 : I;
+    const ParmVarDecl *PVD =
+        Idx < Callee->getNumParams() ? Callee->getParamDecl(Idx) : nullptr;
+    bool NonNull = !ForbiddenNullArgs.empty() && ForbiddenNullArgs[Idx];
+    if (!EvaluateCallArg(PVD, Args[Idx], Call, Info, NonNull)) {
       // If we're checking for a potential constant expression, evaluate all
       // initializers even if some of them fail.
       if (!Info.noteFailure())
         return false;
       Success = false;
-    } else if (!ForbiddenNullArgs.empty() &&
-               ForbiddenNullArgs[Idx] &&
-               ArgValues[Idx].isLValue() &&
-               ArgValues[Idx].isNullPointer()) {
-      Info.CCEDiag(Args[Idx], diag::note_non_null_attribute_failed);
-      if (!Info.noteFailure())
-        return false;
-      Success = false;
     }
   }
   return Success;
 }
 
+/// Perform a trivial copy from Param, which is the parameter of a copy or move
+/// constructor or assignment operator.
+static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param,
+                              const Expr *E, APValue &Result,
+                              bool CopyObjectRepresentation) {
+  // Find the reference argument.
+  CallStackFrame *Frame = Info.CurrentCall;
+  APValue *RefValue = Info.getParamSlot(Frame->Arguments, Param);
+  if (!RefValue) {
+    Info.FFDiag(E);
+    return false;
+  }
+
+  // Copy out the contents of the RHS object.
+  LValue RefLValue;
+  RefLValue.setFrom(Info.Ctx, *RefValue);
+  return handleLValueToRValueConversion(
+      Info, E, Param->getType().getNonReferenceType(), RefLValue, Result,
+      CopyObjectRepresentation);
+}
+
 /// Evaluate a function call.
 static bool HandleFunctionCall(SourceLocation CallLoc,
                                const FunctionDecl *Callee, const LValue *This,
-                               ArrayRef<const Expr *> Args, APValue *ArgValues,
+                               ArrayRef<const Expr *> Args, CallRef Call,
                                const Stmt *Body, EvalInfo &Info,
                                APValue &Result, const LValue *ResultSlot) {
   if (!Info.CheckCallLimit(CallLoc))
     return false;
 
-  CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues);
+  CallStackFrame Frame(Info, CallLoc, Callee, This, Call);
 
   // For a trivial copy or move assignment, perform an APValue copy. This is
   // essential for unions, where the operations performed by the assignment
@@ -5859,11 +6005,9 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
         isReadByLvalueToRvalueConversion(MD->getParent())))) {
     assert(This &&
            (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
-    LValue RHS;
-    RHS.setFrom(Info.Ctx, ArgValues[0]);
     APValue RHSValue;
-    if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS,
-                                        RHSValue, MD->getParent()->isUnion()))
+    if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue,
+                           MD->getParent()->isUnion()))
       return false;
     if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() &&
         !HandleUnionActiveMemberChange(Info, Args[0], *This))
@@ -5897,7 +6041,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
 
 /// Evaluate a constructor call.
 static bool HandleConstructorCall(const Expr *E, const LValue &This,
-                                  APValue *ArgValues,
+                                  CallRef Call,
                                   const CXXConstructorDecl *Definition,
                                   EvalInfo &Info, APValue &Result) {
   SourceLocation CallLoc = E->getExprLoc();
@@ -5914,7 +6058,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
       Info,
       ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries},
       RD->getNumBases());
-  CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
+  CallStackFrame Frame(Info, CallLoc, Definition, &This, Call);
 
   // FIXME: Creating an APValue just to hold a nonexistent return value is
   // wasteful.
@@ -5945,11 +6089,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
       (Definition->getParent()->isUnion() ||
        (Definition->isTrivial() &&
         isReadByLvalueToRvalueConversion(Definition->getParent())))) {
-    LValue RHS;
-    RHS.setFrom(Info.Ctx, ArgValues[0]);
-    return handleLValueToRValueConversion(
-        Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
-        RHS, Result, Definition->getParent()->isUnion());
+    return handleTrivialCopy(Info, Definition->getParamDecl(0), E, Result,
+                             Definition->getParent()->isUnion());
   }
 
   // Reserve space for the struct members.
@@ -6108,12 +6249,13 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
                                   ArrayRef<const Expr*> Args,
                                   const CXXConstructorDecl *Definition,
                                   EvalInfo &Info, APValue &Result) {
-  ArgVector ArgValues(Args.size());
-  if (!EvaluateArgs(Args, ArgValues, Info, Definition))
+  CallScopeRAII CallScope(Info);
+  CallRef Call = Info.CurrentCall->createCall(Definition);
+  if (!EvaluateArgs(Args, Call, Info, Definition))
     return false;
 
-  return HandleConstructorCall(E, This, ArgValues.data(), Definition,
-                               Info, Result);
+  return HandleConstructorCall(E, This, Call, Definition, Info, Result) &&
+         CallScope.destroy();
 }
 
 static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
@@ -6209,7 +6351,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
   if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
     return false;
 
-  CallStackFrame Frame(Info, CallLoc, Definition, &This, nullptr);
+  CallStackFrame Frame(Info, CallLoc, Definition, &This, CallRef());
 
   // We're now in the period of destruction of this object.
   unsigned BasesLeft = RD->getNumBases();
@@ -7197,8 +7339,8 @@ class ExprEvaluatorBase
     LValue CommonLV;
     if (!Evaluate(Info.CurrentCall->createTemporary(
                       E->getOpaqueValue(),
-                      getStorageType(Info.Ctx, E->getOpaqueValue()), false,
-                      CommonLV),
+                      getStorageType(Info.Ctx, E->getOpaqueValue()),
+                      ScopeKind::FullExpression, CommonLV),
                   Info, E->getCommon()))
       return false;
 
@@ -7262,7 +7404,8 @@ class ExprEvaluatorBase
 
         LValue LV;
         if (!Evaluate(Info.CurrentCall->createTemporary(
-                          OVE, getStorageType(Info.Ctx, OVE), false, LV),
+                          OVE, getStorageType(Info.Ctx, OVE),
+                          ScopeKind::FullExpression, LV),
                       Info, OVE->getSourceExpr()))
           return false;
       } else if (SemE == E->getResultExpr()) {
@@ -7285,6 +7428,8 @@ class ExprEvaluatorBase
 
   bool handleCallExpr(const CallExpr *E, APValue &Result,
                      const LValue *ResultSlot) {
+    CallScopeRAII CallScope(Info);
+
     const Expr *Callee = E->getCallee()->IgnoreParens();
     QualType CalleeType = Callee->getType();
 
@@ -7293,7 +7438,8 @@ class ExprEvaluatorBase
     auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
     bool HasQualifier = false;
 
-    ArgVector ArgValues;
+    CallRef Call;
+    bool EvaluatedArgs = false;
 
     // Extract function decl and 'this' pointer from the callee.
     if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
@@ -7326,14 +7472,14 @@ class ExprEvaluatorBase
         return Error(Callee);
       FD = Member;
     } else if (CalleeType->isFunctionPointerType()) {
-      LValue Call;
-      if (!EvaluatePointer(Callee, Call, Info))
+      LValue CalleeLV;
+      if (!EvaluatePointer(Callee, CalleeLV, Info))
         return false;
 
-      if (!Call.getLValueOffset().isZero())
+      if (!CalleeLV.getLValueOffset().isZero())
         return Error(Callee);
       FD = dyn_cast_or_null<FunctionDecl>(
-                             Call.getLValueBase().dyn_cast<const ValueDecl*>());
+          CalleeLV.getLValueBase().dyn_cast<const ValueDecl *>());
       if (!FD)
         return Error(Callee);
       // Don't call function pointers which have been cast to some other type.
@@ -7348,15 +7494,11 @@ class ExprEvaluatorBase
       auto *OCE = dyn_cast<CXXOperatorCallExpr>(E);
       if (OCE && OCE->isAssignmentOp()) {
         assert(Args.size() == 2 && "wrong number of arguments in assignment");
-        if (isa<CXXMethodDecl>(FD)) {
-          // Args[0] is the object argument.
-          if (!EvaluateArgs({Args[1]}, ArgValues, Info, FD))
-            return false;
-        } else {
-          if (!EvaluateArgs({Args[1], Args[0]}, ArgValues, Info, FD))
-            return false;
-          std::swap(ArgValues[0], ArgValues[1]);
-        }
+        Call = Info.CurrentCall->createCall(FD);
+        if (!EvaluateArgs(isa<CXXMethodDecl>(FD) ? Args.slice(1) : Args, Call,
+                          Info, FD, /*RightToLeft=*/true))
+          return false;
+        EvaluatedArgs = true;
       }
 
       // Overloaded operator calls to member functions are represented as normal
@@ -7413,18 +7555,20 @@ class ExprEvaluatorBase
           if (!HandleOperatorNewCall(Info, E, Ptr))
             return false;
           Ptr.moveInto(Result);
-          return true;
+          return CallScope.destroy();
         } else {
-          return HandleOperatorDeleteCall(Info, E);
+          return HandleOperatorDeleteCall(Info, E) && CallScope.destroy();
         }
       }
     } else
       return Error(E);
 
     // Evaluate the arguments now if we've not already done so.
-    if (ArgValues.empty() && !Args.empty() &&
-        !EvaluateArgs(Args, ArgValues, Info, FD))
-      return false;
+    if (!Call) {
+      Call = Info.CurrentCall->createCall(FD);
+      if (!EvaluateArgs(Args, Call, Info, FD))
+        return false;
+    }
 
     SmallVector<QualType, 4> CovariantAdjustmentPath;
     if (This) {
@@ -7447,17 +7591,17 @@ class ExprEvaluatorBase
     // Destructor calls are 
diff erent enough that they have their own codepath.
     if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
       assert(This && "no 'this' pointer for destructor call");
-      assert(ArgValues.empty() && "unexpected destructor arguments");
       return HandleDestruction(Info, E, *This,
-                               Info.Ctx.getRecordType(DD->getParent()));
+                               Info.Ctx.getRecordType(DD->getParent())) &&
+             CallScope.destroy();
     }
 
     const FunctionDecl *Definition = nullptr;
     Stmt *Body = FD->getBody(Definition);
 
     if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition, Body) ||
-        !HandleFunctionCall(E->getExprLoc(), Definition, This, Args,
-                            ArgValues.data(), Body, Info, Result, ResultSlot))
+        !HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Call,
+                            Body, Info, Result, ResultSlot))
       return false;
 
     if (!CovariantAdjustmentPath.empty() &&
@@ -7465,7 +7609,7 @@ class ExprEvaluatorBase
                                          CovariantAdjustmentPath))
       return false;
 
-    return true;
+    return CallScope.destroy();
   }
 
   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
@@ -7929,31 +8073,45 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
       return true;
     }
   }
+
   CallStackFrame *Frame = nullptr;
-  if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
+  unsigned Version = 0;
+  if (VD->hasLocalStorage()) {
     // Only if a local variable was declared in the function currently being
     // evaluated, do we expect to be able to find its value in the current
     // frame. (Otherwise it was likely declared in an enclosing context and
     // could either have a valid evaluatable value (for e.g. a constexpr
     // variable) or be ill-formed (and trigger an appropriate evaluation
     // diagnostic)).
-    if (Info.CurrentCall->Callee &&
-        Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
-      Frame = Info.CurrentCall;
+    CallStackFrame *CurrFrame = Info.CurrentCall;
+    if (CurrFrame->Callee && CurrFrame->Callee->Equals(VD->getDeclContext())) {
+      // Function parameters are stored in some caller's frame. (Usually the
+      // immediate caller, but for an inherited constructor they may be more
+      // distant.)
+      if (auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
+        if (CurrFrame->Arguments) {
+          VD = CurrFrame->Arguments.getOrigParam(PVD);
+          Frame =
+              Info.getCallFrameAndDepth(CurrFrame->Arguments.CallIndex).first;
+          Version = CurrFrame->Arguments.Version;
+        }
+      } else {
+        Frame = CurrFrame;
+        Version = CurrFrame->getCurrentTemporaryVersion(VD);
+      }
     }
   }
 
   if (!VD->getType()->isReferenceType()) {
     if (Frame) {
-      Result.set({VD, Frame->Index,
-                  Info.CurrentCall->getCurrentTemporaryVersion(VD)});
+      Result.set({VD, Frame->Index, Version});
       return true;
     }
     return Success(VD);
   }
 
   APValue *V;
-  if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
+  if (!evaluateVarDeclInit(Info, E, VD, Frame, Version, V))
     return false;
   if (!V->hasValue()) {
     // FIXME: Is it possible for V to be indeterminate here? If so, we should
@@ -7983,12 +8141,16 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
   // value for use outside this evaluation.
   APValue *Value;
   if (E->getStorageDuration() == SD_Static) {
+    // FIXME: What about SD_Thread?
     Value = E->getOrCreateValue(true);
     *Value = APValue();
     Result.set(E);
   } else {
     Value = &Info.CurrentCall->createTemporary(
-        E, E->getType(), E->getStorageDuration() == SD_Automatic, Result);
+        E, E->getType(),
+        E->getStorageDuration() == SD_FullExpression ? ScopeKind::FullExpression
+                                                     : ScopeKind::Block,
+        Result);
   }
 
   QualType Type = Inner->getType();
@@ -8542,7 +8704,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
         return false;
     } else {
       APValue &Value = Info.CurrentCall->createTemporary(
-          SubExpr, SubExpr->getType(), false, Result);
+          SubExpr, SubExpr->getType(), ScopeKind::FullExpression, Result);
       if (!EvaluateInPlace(Value, Info, Result, SubExpr))
         return false;
     }
@@ -9795,8 +9957,8 @@ class TemporaryExprEvaluator
 
   /// Visit an expression which constructs the value of this temporary.
   bool VisitConstructExpr(const Expr *E) {
-    APValue &Value =
-        Info.CurrentCall->createTemporary(E, E->getType(), false, Result);
+    APValue &Value = Info.CurrentCall->createTemporary(
+        E, E->getType(), ScopeKind::FullExpression, Result);
     return EvaluateInPlace(Value, Info, Result, E);
   }
 
@@ -10233,8 +10395,8 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
   if (E->getCommonExpr() &&
       !Evaluate(Info.CurrentCall->createTemporary(
                     E->getCommonExpr(),
-                    getStorageType(Info.Ctx, E->getCommonExpr()), false,
-                    CommonLV),
+                    getStorageType(Info.Ctx, E->getCommonExpr()),
+                    ScopeKind::FullExpression, CommonLV),
                 Info, E->getCommonExpr()->getSourceExpr()))
     return false;
 
@@ -14226,13 +14388,14 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
   } else if (T->isArrayType()) {
     LValue LV;
     APValue &Value =
-        Info.CurrentCall->createTemporary(E, T, false, LV);
+        Info.CurrentCall->createTemporary(E, T, ScopeKind::FullExpression, LV);
     if (!EvaluateArray(E, LV, Value, Info))
       return false;
     Result = Value;
   } else if (T->isRecordType()) {
     LValue LV;
-    APValue &Value = Info.CurrentCall->createTemporary(E, T, false, LV);
+    APValue &Value =
+        Info.CurrentCall->createTemporary(E, T, ScopeKind::FullExpression, LV);
     if (!EvaluateRecord(E, LV, Value, Info))
       return false;
     Result = Value;
@@ -14246,7 +14409,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
     QualType Unqual = T.getAtomicUnqualifiedType();
     if (Unqual->isArrayType() || Unqual->isRecordType()) {
       LValue LV;
-      APValue &Value = Info.CurrentCall->createTemporary(E, Unqual, false, LV);
+      APValue &Value = Info.CurrentCall->createTemporary(
+          E, Unqual, ScopeKind::FullExpression, LV);
       if (!EvaluateAtomic(E, &LV, Value, Info))
         return false;
     } else {
@@ -15255,14 +15419,20 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
     Info.EvalStatus.HasSideEffects = false;
   }
 
-  ArgVector ArgValues(Args.size());
+  CallRef Call = Info.CurrentCall->createCall(Callee);
   for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
        I != E; ++I) {
+    unsigned Idx = I - Args.begin();
+    if (Idx >= Callee->getNumParams())
+      break;
+    const ParmVarDecl *PVD = Callee->getParamDecl(Idx);
     if ((*I)->isValueDependent() ||
-        !Evaluate(ArgValues[I - Args.begin()], Info, *I) ||
-        Info.EvalStatus.HasSideEffects)
+        !EvaluateCallArg(PVD, *I, Call, Info) ||
+        Info.EvalStatus.HasSideEffects) {
       // If evaluation fails, throw away the argument entirely.
-      ArgValues[I - Args.begin()] = APValue();
+      if (APValue *Slot = Info.getParamSlot(Call, PVD))
+        *Slot = APValue();
+    }
 
     // Ignore any side-effects from a failed evaluation. This is safe because
     // they can't interfere with any other argument evaluation.
@@ -15275,8 +15445,7 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
   Info.EvalStatus.HasSideEffects = false;
 
   // Build fake call to Callee.
-  CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
-                       ArgValues.data());
+  CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, Call);
   // FIXME: Missing ExprWithCleanups in enable_if conditions?
   FullExpressionRAII Scope(Info);
   return Evaluate(Value, Info, this) && Scope.destroy() &&
@@ -15334,8 +15503,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
   } else {
     SourceLocation Loc = FD->getLocation();
     HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : nullptr,
-                       Args, /*ArgValues*/ nullptr, FD->getBody(), Info,
-                       Scratch, nullptr);
+                       Args, CallRef(), FD->getBody(), Info, Scratch, nullptr);
   }
 
   return Diags.empty();
@@ -15357,8 +15525,7 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
   Info.CheckingPotentialConstantExpression = true;
 
   // Fabricate a call stack frame to give the arguments a plausible cover story.
-  CallStackFrame Frame(Info, SourceLocation(), FD, /*This*/ nullptr,
-                       /*ArgValues*/ nullptr);
+  CallStackFrame Frame(Info, SourceLocation(), FD, /*This*/ nullptr, CallRef());
 
   APValue ResultScratch;
   Evaluate(ResultScratch, Info, E);

diff  --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
index 3b8274e27369..00ef78426289 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -10,7 +10,7 @@ namespace M {
 
 struct NonLiteral {
   NonLiteral() {}
-  NonLiteral(int) {} // expected-note 2{{here}}
+  NonLiteral(int) {}
   operator int() const { return 0; }
 };
 struct Literal {
@@ -42,8 +42,8 @@ template<typename ...P> struct ConstexprCtor {
 };
 constexpr ConstexprCtor<> f1() { return {}; } // ok
 constexpr ConstexprCtor<int> f2() { return 0; } // ok
-constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
-constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-constexpr constructor 'NonLiteral}}
+constexpr ConstexprCtor<NonLiteral> f3() { return { 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
+constexpr ConstexprCtor<int, NonLiteral> f4() { return { 0, 0 }; } // expected-error {{never produces a constant expression}} expected-note {{non-literal type 'NonLiteral}}
 
 struct VirtBase : virtual S {}; // expected-note {{here}}
 

diff  --git a/clang/test/CXX/except/except.spec/p1.cpp b/clang/test/CXX/except/except.spec/p1.cpp
index 03d75326a643..ef7c828bc7f2 100644
--- a/clang/test/CXX/except/except.spec/p1.cpp
+++ b/clang/test/CXX/except/except.spec/p1.cpp
@@ -55,7 +55,7 @@ namespace noex {
   struct A {};
 
   void g1() noexcept(A()); // expected-error {{not contextually convertible}}
-  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{read of non-const variable 'b'}} expected-note {{here}}
+  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{function parameter 'b' with unknown value}} expected-note {{here}}
 
 }
 

diff  --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index 2ab629a6d0dd..e7b6929199ff 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -62,11 +62,11 @@ namespace NonConstExprReturn {
   constexpr const int *address_of(const int &a) {
     return &a;
   }
-  constexpr const int *return_param(int n) { // expected-note {{declared here}}
+  constexpr const int *return_param(int n) {
     return address_of(n);
   }
   struct S {
-    int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
+    int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
   };
 }
 
@@ -427,13 +427,12 @@ namespace PseudoDtor {
     int n : (k.~I(), 1); // expected-error {{constant expression}} expected-note {{visible outside that expression}}
   };
 
-  // FIXME: It's unclear whether this should be accepted in C++20 mode. The parameter is destroyed twice here.
-  constexpr int f(int a = 1) { // cxx11-error {{constant expression}}
+  constexpr int f(int a = 1) { // cxx11-error {{constant expression}} expected-note {{destroying object 'a' whose lifetime has already ended}}
     return (
-        a.~I(), // cxx11-note 2{{pseudo-destructor}}
+        a.~I(), // cxx11-note {{pseudo-destructor}}
         0);
   }
-  static_assert(f() == 0, ""); // cxx11-error {{constant expression}} cxx11-note {{in call}}
+  static_assert(f() == 0, ""); // expected-error {{constant expression}}
 
   // This is OK in C++20: the union has no active member after the
   // pseudo-destructor call, so the union destructor has no effect.

diff  --git a/clang/test/OpenMP/critical_messages.cpp b/clang/test/OpenMP/critical_messages.cpp
index 4fc2b201c820..8536caf224e3 100644
--- a/clang/test/OpenMP/critical_messages.cpp
+++ b/clang/test/OpenMP/critical_messages.cpp
@@ -65,7 +65,7 @@ int tmain(int argc, char **argv) { // expected-note {{declared here}}
   foo();
   #pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   foo();
-  #pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
+  #pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note 0+{{constant expression}}
   foo();
   #pragma omp critical (name) hint(N) // expected-error {{argument to 'hint' clause must be a strictly positive integer value}} expected-error {{constructs with the same name must have a 'hint' clause with the same value}} expected-note {{'hint' clause with value '4'}}
   foo();
@@ -128,7 +128,7 @@ int main(int argc, char **argv) { // expected-note {{declared here}}
   foo();
   #pragma omp critical (name2) hint(+ // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
   foo();
-  #pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note {{read of non-const variable 'argc' is not allowed in a constant expression}}
+  #pragma omp critical (name2) hint(argc) // expected-error {{integral constant expression}} expected-note 0+{{constant expression}}
   foo();
   #pragma omp critical (name) hint(23) // expected-note {{previous 'hint' clause with value '23'}}
   foo();

diff  --git a/clang/test/OpenMP/distribute_parallel_for_simd_safelen_messages.cpp b/clang/test/OpenMP/distribute_parallel_for_simd_safelen_messages.cpp
index eba65f733fcf..04f75e360577 100644
--- a/clang/test/OpenMP/distribute_parallel_for_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/distribute_parallel_for_simd_safelen_messages.cpp
@@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
 
 #pragma omp target
 #pragma omp teams
-#pragma omp distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/distribute_simd_safelen_messages.cpp b/clang/test/OpenMP/distribute_simd_safelen_messages.cpp
index 51d677829486..8c3c009c2a81 100644
--- a/clang/test/OpenMP/distribute_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/distribute_simd_safelen_messages.cpp
@@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
 
 #pragma omp target
 #pragma omp teams
-#pragma omp distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/distribute_simd_simdlen_messages.cpp b/clang/test/OpenMP/distribute_simd_simdlen_messages.cpp
index 51d677829486..8c3c009c2a81 100644
--- a/clang/test/OpenMP/distribute_simd_simdlen_messages.cpp
+++ b/clang/test/OpenMP/distribute_simd_simdlen_messages.cpp
@@ -39,7 +39,7 @@ T tmain(T argc, S **argv) {
 
 #pragma omp target
 #pragma omp teams
-#pragma omp distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_safelen_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_safelen_messages.cpp
index 31dfb7c8024e..3061dff6709b 100644
--- a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_safelen_messages.cpp
@@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
 #pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
-#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_simdlen_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_simdlen_messages.cpp
index 14865e593129..b67ca29634dc 100644
--- a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_simdlen_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_simdlen_messages.cpp
@@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
 #pragma omp target teams distribute parallel for simd safelen () // expected-error {{expected expression}}
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
-#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp target teams distribute parallel for simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++)
     argv[0][i] = argv[0][i] - argv[0][i-ST];
 

diff  --git a/clang/test/OpenMP/target_teams_distribute_simd_safelen_messages.cpp b/clang/test/OpenMP/target_teams_distribute_simd_safelen_messages.cpp
index a472b8eddee8..75a86e6890d5 100644
--- a/clang/test/OpenMP/target_teams_distribute_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_simd_safelen_messages.cpp
@@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
 #pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
-#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/target_teams_distribute_simd_simdlen_messages.cpp b/clang/test/OpenMP/target_teams_distribute_simd_simdlen_messages.cpp
index 489bb808db54..f84dd17f9fb0 100644
--- a/clang/test/OpenMP/target_teams_distribute_simd_simdlen_messages.cpp
+++ b/clang/test/OpenMP/target_teams_distribute_simd_simdlen_messages.cpp
@@ -31,7 +31,7 @@ T tmain(T argc, S **argv) {
 #pragma omp target teams distribute simd safelen () // expected-error {{expected expression}}
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
-#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp target teams distribute simd safelen (argc // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/teams_distribute_parallel_for_simd_safelen_messages.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_simd_safelen_messages.cpp
index 122b9cbe098b..78d742c9b3ae 100644
--- a/clang/test/OpenMP/teams_distribute_parallel_for_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/teams_distribute_parallel_for_simd_safelen_messages.cpp
@@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
 #pragma omp target
-#pragma omp teams distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp teams distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/teams_distribute_parallel_for_simd_simdlen_messages.cpp b/clang/test/OpenMP/teams_distribute_parallel_for_simd_simdlen_messages.cpp
index 122b9cbe098b..78d742c9b3ae 100644
--- a/clang/test/OpenMP/teams_distribute_parallel_for_simd_simdlen_messages.cpp
+++ b/clang/test/OpenMP/teams_distribute_parallel_for_simd_simdlen_messages.cpp
@@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
 #pragma omp target
-#pragma omp teams distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp teams distribute parallel for simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/teams_distribute_simd_safelen_messages.cpp b/clang/test/OpenMP/teams_distribute_simd_safelen_messages.cpp
index 4efede29baee..3cf70dbdc9ef 100644
--- a/clang/test/OpenMP/teams_distribute_simd_safelen_messages.cpp
+++ b/clang/test/OpenMP/teams_distribute_simd_safelen_messages.cpp
@@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
 #pragma omp target
-#pragma omp teams distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp teams distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/OpenMP/teams_distribute_simd_simdlen_messages.cpp b/clang/test/OpenMP/teams_distribute_simd_simdlen_messages.cpp
index 4efede29baee..3cf70dbdc9ef 100644
--- a/clang/test/OpenMP/teams_distribute_simd_simdlen_messages.cpp
+++ b/clang/test/OpenMP/teams_distribute_simd_simdlen_messages.cpp
@@ -35,7 +35,7 @@ T tmain(T argc, S **argv) {
   for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
 
 #pragma omp target
-#pragma omp teams distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 2 {{read of non-const variable 'argc' is not allowed in a constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
+#pragma omp teams distribute simd safelen (argc  // expected-note {{to match this '('}} expected-error 2 {{integral constant expression}} expected-note 0+{{constant expression}} expected-error {{expected ')'}}
   for (int i = ST; i < N; i++) 
     argv[0][i] = argv[0][i] - argv[0][i-ST];
   

diff  --git a/clang/test/Sema/builtin-expect-with-probability-avr.cpp b/clang/test/Sema/builtin-expect-with-probability-avr.cpp
index 1dbb1d52396a..1767480134a2 100644
--- a/clang/test/Sema/builtin-expect-with-probability-avr.cpp
+++ b/clang/test/Sema/builtin-expect-with-probability-avr.cpp
@@ -5,7 +5,7 @@ void test(int x, double p) { // expected-note {{declared here}}
   dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
   dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
   dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
-  dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{read of non-constexpr variable 'p' is not allowed in a constant expression}}
+  dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{function parameter 'p' with unknown value}}
   dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
   dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
   dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}

diff  --git a/clang/test/Sema/builtin-expect-with-probability.cpp b/clang/test/Sema/builtin-expect-with-probability.cpp
index 3aa20cb0e6dd..e05174f70673 100644
--- a/clang/test/Sema/builtin-expect-with-probability.cpp
+++ b/clang/test/Sema/builtin-expect-with-probability.cpp
@@ -43,7 +43,7 @@ void test(int x, double p) { // expected-note {{declared here}}
   dummy = __builtin_expect_with_probability(x > 0, 1, 0.9);
   dummy = __builtin_expect_with_probability(x > 0, 1, 1.1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
   dummy = __builtin_expect_with_probability(x > 0, 1, -1); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
-  dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{read of non-constexpr variable 'p' is not allowed in a constant expression}}
+  dummy = __builtin_expect_with_probability(x > 0, 1, p); // expected-error {{probability argument to __builtin_expect_with_probability must be constant floating-point expression}} expected-note {{function parameter 'p'}}
   dummy = __builtin_expect_with_probability(x > 0, 1, "aa"); // expected-error {{cannot initialize a parameter of type 'double' with an lvalue of type 'const char [3]'}}
   dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_nan("")); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}
   dummy = __builtin_expect_with_probability(x > 0, 1, __builtin_inf()); // expected-error {{probability argument to __builtin_expect_with_probability is outside the range [0.0, 1.0]}}

diff  --git a/clang/test/Sema/c89.c b/clang/test/Sema/c89.c
index 1c0494d8e5a3..89eda9362608 100644
--- a/clang/test/Sema/c89.c
+++ b/clang/test/Sema/c89.c
@@ -65,7 +65,7 @@ void test10 (int x[*]); /* expected-warning {{variable length arrays are a C99 f
 void test11 (int x[static 4]); /* expected-warning {{static array size is a C99 feature}} */
 
 void test12 (int x[const 4]) { /* expected-warning {{qualifier in array size is a C99 feature}} */
-  int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} expected-note {{parameter 'x'}} */
+  int Y[x[1]]; /* expected-warning {{variable length arrays are a C99 feature}} */
 }
 
 /* PR4074 */

diff  --git a/clang/test/SemaCUDA/constexpr-variables.cu b/clang/test/SemaCUDA/constexpr-variables.cu
index 6e17a0856838..aa88cbadb73f 100644
--- a/clang/test/SemaCUDA/constexpr-variables.cu
+++ b/clang/test/SemaCUDA/constexpr-variables.cu
@@ -17,7 +17,7 @@ __host__ __device__ void foo(const T **a) {
   constexpr T e = sizeof(a);
   constexpr T f = **a;
   // expected-error at -1 {{constexpr variable 'f' must be initialized by a constant expression}}
-  // expected-note at -2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
+  // expected-note at -2 {{}}
   a[0] = &b;
   a[1] = &c;
   a[2] = &d;
@@ -30,7 +30,7 @@ __device__ void device_fun(const int **a) {
   static constexpr int c = sizeof(a);
   constexpr int d = **a;
   // expected-error at -1 {{constexpr variable 'd' must be initialized by a constant expression}}
-  // expected-note at -2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
+  // expected-note at -2 {{}}
   a[0] = &b;
   a[1] = &c;
   foo(a);
@@ -43,7 +43,7 @@ void host_fun(const int **a) {
   static constexpr int c = sizeof(a);
   constexpr int d = **a;
   // expected-error at -1 {{constexpr variable 'd' must be initialized by a constant expression}}
-  // expected-note at -2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
+  // expected-note at -2 {{}}
   a[0] = &b;
   a[1] = &c;
   foo(a);
@@ -55,7 +55,7 @@ __host__ __device__ void host_device_fun(const int **a) {
   static constexpr int c = sizeof(a);
   constexpr int d = **a;
   // expected-error at -1 {{constexpr variable 'd' must be initialized by a constant expression}}
-  // expected-note at -2 {{read of non-constexpr variable 'a' is not allowed in a constant expression}}
+  // expected-note at -2 {{}}
   a[0] = &b;
   a[1] = &c;
   foo(a);

diff  --git a/clang/test/SemaCXX/c99-variable-length-array-cxx11.cpp b/clang/test/SemaCXX/c99-variable-length-array-cxx11.cpp
index 20eceec5032d..1360a20bfe8c 100644
--- a/clang/test/SemaCXX/c99-variable-length-array-cxx11.cpp
+++ b/clang/test/SemaCXX/c99-variable-length-array-cxx11.cpp
@@ -18,12 +18,12 @@ struct POD {
 
 // We allow VLAs of POD types, only.
 void vla(int N) { // expected-note 5{{here}}
-  int array1[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
-  POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
-  StillPOD array3[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
-  StillPOD2 array4[N][3]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{variable 'N'}}
+  int array1[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
+  POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
+  StillPOD array3[N]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
+  StillPOD2 array4[N][3]; // expected-warning{{variable length arrays are a C99 feature}} expected-note {{parameter 'N'}}
   NonPOD array5[N]; // expected-error{{no matching constructor for initialization of 'NonPOD [N]'}}
-  // expected-warning at -1{{variable length arrays are a C99 feature}} expected-note at -1 {{variable 'N'}}
+  // expected-warning at -1{{variable length arrays are a C99 feature}} expected-note at -1 {{parameter 'N'}}
   // expected-note at -16{{candidate constructor not viable}}
   // expected-note at -18{{candidate constructor (the implicit copy constructor) not viable}}
   // expected-note at -19{{candidate constructor (the implicit move constructor) not viable}}

diff  --git a/clang/test/SemaCXX/c99-variable-length-array.cpp b/clang/test/SemaCXX/c99-variable-length-array.cpp
index d5c3845d1e2f..5f6337e1db06 100644
--- a/clang/test/SemaCXX/c99-variable-length-array.cpp
+++ b/clang/test/SemaCXX/c99-variable-length-array.cpp
@@ -13,6 +13,7 @@ struct POD {
 };
 
 // expected-note@* 1+{{read of non-const variable}}
+// expected-note@* 1+{{function parameter}}
 // expected-note@* 1+{{declared here}}
 
 // We allow VLAs of POD types, only.

diff  --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 4b844177790a..f40b42fa18e0 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -217,11 +217,11 @@ namespace ParameterScopes {
 
   const int k = 42;
   constexpr const int &ObscureTheTruth(const int &a) { return a; }
-  constexpr const int &MaybeReturnJunk(bool b, const int a) { // expected-note 2{{declared here}}
+  constexpr const int &MaybeReturnJunk(bool b, const int a) {
     return ObscureTheTruth(b ? a : k);
   }
   static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok
-  constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
+  constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
 
   constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
     return ObscureTheTruth(b ? a : k);
@@ -230,7 +230,7 @@ namespace ParameterScopes {
   constexpr int b = MaybeReturnNonstaticRef(true, 0); // ok
 
   constexpr int InternalReturnJunk(int n) {
-    return MaybeReturnJunk(true, n); // expected-note {{read of variable whose lifetime has ended}}
+    return MaybeReturnJunk(true, n); // expected-note {{read of object outside its lifetime}}
   }
   constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
 
@@ -1568,7 +1568,7 @@ namespace RecursiveOpaqueExpr {
 namespace VLASizeof {
 
   void f(int k) { // expected-note {{here}}
-    int arr[k]; // expected-warning {{C99}} expected-note {{non-const variable 'k'}}
+    int arr[k]; // expected-warning {{C99}} expected-note {{function parameter 'k'}}
     constexpr int n = 1 +
         sizeof(arr) // expected-error {{constant expression}}
         * 3;
@@ -1928,9 +1928,9 @@ namespace Lifetime {
     int n = 0;
     constexpr int f() const { return 0; }
   };
-  constexpr Q *out_of_lifetime(Q q) { return &q; } // expected-warning {{address of stack}} expected-note 2{{declared here}}
-  constexpr int k3 = out_of_lifetime({})->n; // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}}
-  constexpr int k4 = out_of_lifetime({})->f(); // expected-error {{constant expression}} expected-note {{member call on variable whose lifetime has ended}}
+  constexpr Q *out_of_lifetime(Q q) { return &q; } // expected-warning {{address of stack}}
+  constexpr int k3 = out_of_lifetime({})->n; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}}
+  constexpr int k4 = out_of_lifetime({})->f(); // expected-error {{constant expression}} expected-note {{member call on object outside its lifetime}}
 
   constexpr int null = ((Q*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{member call on dereferenced null pointer}}
 
@@ -2252,7 +2252,7 @@ namespace ns1 {
 void f(char c) { //expected-note2{{declared here}}
   struct X {
     static constexpr char f() { //expected-error{{never produces a constant expression}}
-      return c; //expected-error{{reference to local}} expected-note{{non-const variable}}
+      return c; //expected-error{{reference to local}} expected-note{{function parameter}}
     }
   };
   int I = X::f();
@@ -2312,7 +2312,7 @@ namespace array_size {
   template<typename T> void f1(T t) {
     constexpr int k = t.size();
   }
-  template<typename T> void f2(const T &t) {
+  template<typename T> void f2(const T &t) { // expected-note {{declared here}}
     constexpr int k = t.size(); // expected-error {{constant}} expected-note {{function parameter 't' with unknown value cannot be used in a constant expression}}
   }
   template<typename T> void f3(const T &t) {

diff  --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 344797bafb11..2aea2577d972 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1415,3 +1415,16 @@ namespace PR45350 {
   //   decreasing address
   static_assert(f(6) == 543210);
 }
+
+namespace PR47805 {
+  struct A {
+    bool bad = true;
+    constexpr ~A() { if (bad) throw; }
+  };
+  constexpr bool f(A a) { a.bad = false; return true; }
+  constexpr bool b = f(A());
+
+  struct B { B *p = this; };
+  constexpr bool g(B b) { return &b == b.p; }
+  static_assert(g({}));
+}

diff  --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 2412c9d4db74..305cc3e976b0 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -17,7 +17,7 @@ namespace std {
 }
 
 template<typename T> constexpr bool has_type(...) { return false; }
-template<typename T> constexpr bool has_type(T) { return true; }
+template<typename T> constexpr bool has_type(T&) { return true; }
 
 std::initializer_list il = {1, 2, 3, 4, 5};
 

diff  --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 3231107add09..ecf8c1e0f5bd 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -238,7 +238,7 @@ constexpr int f_c(int i) {
 // expected-note at -1 {{declared here}}
   int t = f(i);
 // expected-error at -1 {{is not a constant expression}}
-// expected-note at -2 {{read of non-const variable}}
+// expected-note at -2 {{function parameter}}
   return f(0);  
 }
 
@@ -254,7 +254,7 @@ auto l1 = [](int i) constexpr {
 // expected-note at -1 {{declared here}}
   int t = f(i);
 // expected-error at -1 {{is not a constant expression}}
-// expected-note at -2 {{read of non-const variable}}
+// expected-note at -2 {{function parameter}}
   return f(0);  
 };
 

diff  --git a/clang/test/SemaCXX/integer-overflow.cpp b/clang/test/SemaCXX/integer-overflow.cpp
index c6167b9c70ea..c4d0d4084def 100644
--- a/clang/test/SemaCXX/integer-overflow.cpp
+++ b/clang/test/SemaCXX/integer-overflow.cpp
@@ -85,8 +85,7 @@ uint64_t check_integer_overflows(int i) { //expected-note 0+{{declared here}}
 // expected-warning at +1 {{overflow in expression; result is 537919488 with type 'int'}}
   case 1 + static_cast<uint64_t>(4609 * 1024 * 1024):
     return 7;
-// expected-error at +2 {{expression is not an integral constant expression}}
-// expected-note at +1 {{read of non-const variable 'i' is not allowed in a constant expression}}
+// expected-error at +1 {{expression is not an integral constant expression}}
   case ((uint64_t)(4608 * 1024 * 1024 * i)):
     return 8;
 // expected-warning at +1 {{overflow in expression; result is 536870912 with type 'int'}}

diff  --git a/clang/test/SemaCXX/vla-construct.cpp b/clang/test/SemaCXX/vla-construct.cpp
index 32526c24b0e0..5a7d83342542 100644
--- a/clang/test/SemaCXX/vla-construct.cpp
+++ b/clang/test/SemaCXX/vla-construct.cpp
@@ -23,8 +23,8 @@ void print(int n, int a, int b, int c, int d) {
 void test(int n) {
   S array_t[n][n+1];
 # ifdef PE
-   // expected-error at -2 {{variable length arrays are a C99 feature}} expected-note at -2 {{read of non-const}} expected-note at -3 {{here}}
-   // expected-error at -3 {{variable length arrays are a C99 feature}} expected-note at -3 {{read of non-const}} expected-note at -4 {{here}}
+   // expected-error at -2 {{variable length arrays are a C99 feature}} expected-note at -2 {{parameter}} expected-note at -3 {{here}}
+   // expected-error at -3 {{variable length arrays are a C99 feature}} expected-note at -3 {{parameter}} expected-note at -4 {{here}}
 # endif
   int sizeof_S = sizeof(S);
   int sizeof_array_t_0_0 = sizeof(array_t[0][0]);

diff  --git a/clang/test/SemaCXX/warn-vla.cpp b/clang/test/SemaCXX/warn-vla.cpp
index 3514264efb2a..00ac7c7a5c47 100644
--- a/clang/test/SemaCXX/warn-vla.cpp
+++ b/clang/test/SemaCXX/warn-vla.cpp
@@ -1,27 +1,27 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
 
 void test1(int n) { // expected-note {{here}}
-  int v[n]; // expected-warning {{variable length array}} expected-note {{variable 'n'}}
+  int v[n]; // expected-warning {{variable length array}} expected-note {{parameter 'n'}}
 }
 
-void test2(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
+void test2(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
 }
 
-void test3(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
+void test3(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
 
 template<typename T>
 void test4(int n) { // expected-note {{here}}
-  int v[n]; // expected-warning {{variable length array}} expected-note {{variable 'n'}}
+  int v[n]; // expected-warning {{variable length array}} expected-note {{parameter 'n'}}
 }
 
 template<typename T>
-void test5(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
+void test5(int n, int v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
 }
 
 template<typename T>
-void test6(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
+void test6(int n, int v[n]); // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
 
 template<typename T>
-void test7(int n, T v[n]) { // expected-warning {{variable length array}} expected-note {{variable 'n'}} expected-note {{here}}
+void test7(int n, T v[n]) { // expected-warning {{variable length array}} expected-note {{parameter 'n'}} expected-note {{here}}
 }
 

diff  --git a/clang/test/SemaTemplate/typo-dependent-name.cpp b/clang/test/SemaTemplate/typo-dependent-name.cpp
index 88b2fc373b1f..6a67e10dc868 100644
--- a/clang/test/SemaTemplate/typo-dependent-name.cpp
+++ b/clang/test/SemaTemplate/typo-dependent-name.cpp
@@ -34,12 +34,13 @@ struct Y {
   struct Inner : Y { // expected-note {{declared here}}
   };
 
-  bool f(T other) {
+  bool f(T other) { // expected-note {{declared here}}
     // We can determine that 'inner' does not exist at parse time, so can
     // perform typo correction in this case.
     return this->inner<other>::z; // expected-error {{no template named 'inner' in 'Y<T>'; did you mean 'Inner'?}}
+    // expected-error at -1 {{constant expression}} expected-note at -1 {{function parameter 'other'}}
   }
 };
 
 struct Q { constexpr operator int() { return 0; } };
-void use_y(Y<Q> x) { x.f(Q()); }
+void use_y(Y<Q> x) { x.f(Q()); } // expected-note {{instantiation of}}


        


More information about the cfe-commits mailing list