ilya-biryukov created this revision.
Herald added a subscriber: martong.
Herald added a reviewer: shafik.
Herald added a project: All.
ilya-biryukov requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

They must be evaluated in the context where default argument is actually
used during a call, not in a parameter list where default argument is specified.

Fixes #56379.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D132941

Files:
  clang/include/clang/AST/CurrentSourceLocExprScope.h
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/ExprCXX.h
  clang/include/clang/AST/Stmt.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/Expr.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/CodeGenCXX/builtin-source-location.cpp
  clang/test/SemaCXX/source_location.cpp
  clang/test/SemaCXX/source_location_consteval.cpp

Index: clang/test/SemaCXX/source_location_consteval.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/source_location_consteval.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+namespace std {
+class source_location {
+  struct __impl;
+
+public:
+  static consteval source_location current(const __impl *__p = __builtin_source_location()) noexcept {
+    source_location __loc;
+    __loc.__m_impl = __p;
+    return __loc;
+  }
+  constexpr source_location() = default;
+  constexpr source_location(source_location const &) = default;
+  constexpr unsigned int line() const noexcept { return __m_impl ? __m_impl->_M_line : 0; }
+  constexpr unsigned int column() const noexcept { return __m_impl ? __m_impl->_M_column : 0; }
+  constexpr const char *file() const noexcept { return __m_impl ? __m_impl->_M_file_name : ""; }
+  constexpr const char *function() const noexcept { return __m_impl ? __m_impl->_M_function_name : ""; }
+
+private:
+  // Note: The type name "std::source_location::__impl", and its constituent
+  // field-names are required by __builtin_source_location().
+  struct __impl {
+    const char *_M_file_name;
+    const char *_M_function_name;
+    unsigned _M_line;
+    unsigned _M_column;
+  };
+  const __impl *__m_impl = nullptr;
+
+public:
+  using public_impl_alias = __impl;
+};
+} // namespace std
+
+using SL = std::source_location;
+
+constexpr bool is_equal(const char *LHS, const char *RHS) {
+  while (*LHS != 0 && *RHS != 0) {
+    if (*LHS != *RHS)
+      return false;
+    ++LHS;
+    ++RHS;
+  }
+  return *LHS == 0 && *RHS == 0;
+}
+
+constexpr SL get_sl(SL l = SL::current()) { return l; }
+SL get_sl_not_const(SL l = SL::current()) { return l; }
+
+#line 700 "CheckDefaultArg.h"
+constexpr SL l = get_sl();
+static_assert(l.line() == 700);
+static_assert(is_equal(l.file(), "CheckDefaultArg.h"));
+
+int test() {
+  static_assert(is_equal(get_sl().function(), __PRETTY_FUNCTION__));
+  static_assert(get_sl().line() ==  __LINE__);
+  return get_sl().line() + get_sl_not_const().line();
+}
Index: clang/test/SemaCXX/source_location.cpp
===================================================================
--- clang/test/SemaCXX/source_location.cpp
+++ clang/test/SemaCXX/source_location.cpp
@@ -364,8 +364,8 @@
 template <class T>
 void func_template_tests() {
   constexpr auto P = test_func_template(42);
-  //static_assert(is_equal(P.first.function(), __func__), "");
-  //static_assert(!is_equal(P.second.function(), __func__), "");
+  static_assert(is_equal(P.first.function(), __PRETTY_FUNCTION__), "");
+  static_assert(!is_equal(P.second.function(), __PRETTY_FUNCTION__), "");
 }
 template void func_template_tests<int>();
 
Index: clang/test/CodeGenCXX/builtin-source-location.cpp
===================================================================
--- clang/test/CodeGenCXX/builtin-source-location.cpp
+++ clang/test/CodeGenCXX/builtin-source-location.cpp
@@ -13,12 +13,12 @@
 namespace std {
 class source_location {
 public:
-  static constexpr source_location current(const void *__p = __builtin_source_location()) noexcept {
+  static consteval source_location current(const void *__p = __builtin_source_location()) noexcept {
     source_location __loc;
     __loc.__m_impl = static_cast<const __impl *>(__p);
     return __loc;
   }
-  static source_location bad_current(const void *__p = __builtin_source_location()) noexcept {
+  static constexpr source_location bad_current(const void *__p = __builtin_source_location()) noexcept {
     return current(__p);
   }
   constexpr source_location() = default;
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1747,6 +1747,9 @@
   Record.AddDeclRef(E->getParam());
   Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
   Record.AddSourceLocation(E->getUsedLocation());
+  Record.push_back(E->hasRewrittenArg());
+  if (E->hasRewrittenArg()) 
+    Record.AddStmt(E->getExpr());
   Code = serialization::EXPR_CXX_DEFAULT_ARG;
 }
 
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1827,6 +1827,9 @@
   E->Param = readDeclAs<ParmVarDecl>();
   E->UsedContext = readDeclAs<DeclContext>();
   E->CXXDefaultArgExprBits.Loc = readSourceLocation();
+  E->CXXDefaultArgExprBits.HasRewrittenArg = Record.readInt();
+  if (E->CXXDefaultArgExprBits.HasRewrittenArg)
+    *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
 }
 
 void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
@@ -3817,7 +3820,9 @@
       break;
 
     case EXPR_CXX_DEFAULT_ARG:
-      S = new (Context) CXXDefaultArgExpr(Empty);
+      S = CXXDefaultArgExpr::CreateEmpty(
+          Context,
+          /*HasRewrittenArg*/ Record[ASTStmtReader::NumExprFields]);
       break;
 
     case EXPR_CXX_DEFAULT_INIT:
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -847,8 +847,9 @@
   if (!Attr)
     return;
   for (unsigned I = 0; I != NumParams; ++I) {
+    Expr *Dummy;
     (void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor,
-                                   Ctor->getParamDecl(I));
+                                 Ctor->getParamDecl(I), Dummy);
     CleanupVarDeclMarking();
   }
 }
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1051,7 +1051,8 @@
       // We don't keep the instantiated default argument expressions around so
       // we must rebuild them here.
       for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) {
-        if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)))
+        Expr* Dummy;
+        if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I), Dummy))
           return true;
       }
     }
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17,6 +17,9 @@
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CurrentSourceLocExprScope.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/EvaluatedExprVisitor.h"
@@ -44,9 +47,11 @@
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Overload.h"
+#include "clang/Sema/Ownership.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaFixItUtils.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
@@ -5848,8 +5853,30 @@
       ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc);
 }
 
+static bool IsStdSourceLocationCurrent(Decl* D) {
+  auto *F = D ? dyn_cast<FunctionDecl>(D) : nullptr;
+  auto *FuncName = F ? F->getIdentifier() : nullptr;
+  if (!FuncName || !FuncName->isStr("current") || !F->isConsteval())
+    return false;
+  auto *Cls = dyn_cast<RecordDecl>(F->getDeclContext());
+  auto *ClsName = Cls ? Cls->getIdentifier() : nullptr;
+  return ClsName && ClsName->isStr("source_location") && Cls->isInStdNamespace();
+}
+
+static bool IsCallToStdSourceLocationCurrent(Expr* E) {
+  CallExpr *Call = dyn_cast<CallExpr>(E);
+  auto *Callee = Call ? Call->getCalleeDecl() : nullptr;
+  return Callee && IsStdSourceLocationCurrent(Callee);
+}
+
+static ExprResult EvaluateSourceLocations(Sema &S, ParmVarDecl *Param,
+                                          SourceLocation CallLoc,
+                                          DeclContext *UsedContext);
+
 bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
-                                  ParmVarDecl *Param) {
+                                  ParmVarDecl *Param, Expr *&RewrittenArg) {
+  RewrittenArg = nullptr;
+
   if (Param->hasUnparsedDefaultArg()) {
     // If we've already cleared out the location for the default argument,
     // that means we're parsing it right now.
@@ -5873,6 +5900,12 @@
 
   assert(Param->hasInit() && "default argument but no initializer?");
 
+  ExprResult NewArg = EvaluateSourceLocations(*this, Param, CallLoc, CurContext);
+  if (NewArg.isInvalid())
+    return true;
+  if (NewArg.get() != Param->getDefaultArg())
+    RewrittenArg = NewArg.get();
+
   // If the default expression creates temporaries, we need to
   // push them to the current stack of expression temporaries so they'll
   // be properly destroyed.
@@ -5905,9 +5938,11 @@
 ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
                                         FunctionDecl *FD, ParmVarDecl *Param) {
   assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
-  if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+  Expr* RewrittenArg = nullptr;
+  if (CheckCXXDefaultArgExpr(CallLoc, FD, Param, RewrittenArg))
     return ExprError();
-  return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
+  return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext,
+                                   RewrittenArg);
 }
 
 Sema::VariadicCallType
@@ -17519,13 +17554,20 @@
 }
 
 static void EvaluateAndDiagnoseImmediateInvocation(
-    Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate) {
+    Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate, bool InDefaultArg) {
   llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
   Expr::EvalResult Eval;
   Eval.Diag = &Notes;
   ConstantExpr *CE = Candidate.getPointer();
+  // [support.srcloc.cons]p2.
+  // Any call to current that appears as a default argument ([dcl.fct.default]),
+  // or as a subexpression thereof, should correspond to the location of the
+  // invocation of the function that uses the default argument ([expr.call]).
+  if (InDefaultArg && IsCallToStdSourceLocationCurrent(CE->getSubExpr()))
+    return; // Postpone evaluation until we see the context.
   bool Result = CE->EvaluateAsConstantExpr(
-      Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation);
+      Eval, SemaRef.getASTContext(), ConstantExprKind::ImmediateInvocation,
+      SemaRef.OverridenSourceLocs);
   if (!Result || !Notes.empty()) {
     Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit();
     if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr))
@@ -17546,6 +17588,51 @@
   CE->MoveIntoResult(Eval.Val, SemaRef.getASTContext());
 }
 
+static ExprResult EvaluateSourceLocations(Sema &S, ParmVarDecl* Param,
+                                          SourceLocation CallLoc,
+                                          DeclContext *UsedContext) {
+  struct Transform : TreeTransform<Transform> {
+    using TreeTransform::TreeTransform;
+
+    bool AlwaysRebuild() { return OverrideAlwaysRebuild; }
+
+    ExprResult TransformCallExpr(CallExpr* Call) {
+      if (!IsCallToStdSourceLocationCurrent(Call))
+        return TreeTransform::TransformCallExpr(Call);
+      // Rebuild the call so it gets to the list of immedicate invocations.
+      llvm::SaveAndRestore<bool> Guard(OverrideAlwaysRebuild, true);
+      return TreeTransform::TransformCallExpr(Call);
+    }
+
+  private:
+    bool OverrideAlwaysRebuild = false;
+  };
+  // Force evaluation of calls to source_location::current().
+  // TODO(HACK): potentially evaluated is clearly wrong in some cases?
+  CurrentSourceLocExprScope Locs;
+  CurrentSourceLocExprScope::SourceLocExprScopeGuard LG(
+      SourceLocExpr::Context{CallLoc, UsedContext}, Locs);
+  llvm::SaveAndRestore<CurrentSourceLocExprScope *> SwapLocs(
+      S.OverridenSourceLocs, &Locs);
+
+  EnterExpressionEvaluationContext Eval(
+      S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
+      Sema::ReuseLambdaContextDecl_t{});
+  ExprResult NewArg = Transform(S).TransformExpr(Param->getDefaultArg());
+  if (NewArg.isUsable() && NewArg.get() != Param->getDefaultArg()) {
+    NewArg = S.ConvertParamDefaultArgument(Param, NewArg.get(),
+                                           NewArg.get()->getBeginLoc());
+  }
+  if (NewArg.isInvalid())
+    return NewArg;
+  // Mimic the logic of ParmVarDecl::getDefaultArg().
+  if (auto *E = dyn_cast_or_null<FullExpr>(NewArg.get())) {
+    if (!isa<ConstantExpr>(E))
+      return E->getSubExpr();
+  }
+  return NewArg;
+}
+
 static void RemoveNestedImmediateInvocation(
     Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec,
     SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator It) {
@@ -17664,7 +17751,8 @@
   }
   for (auto CE : Rec.ImmediateInvocationCandidates)
     if (!CE.getInt())
-      EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
+      EvaluateAndDiagnoseImmediateInvocation(
+          SemaRef, CE, /*InDefaultArg=*/Rec.isPotentiallyEvaluatedIfUsed());
   for (auto DR : Rec.ReferenceToConsteval) {
     auto *FD = cast<FunctionDecl>(DR->getDecl());
     SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -6142,7 +6142,8 @@
     // that we can properly codegen the constructor closure.
     if (!Class->isDependentContext()) {
       for (ParmVarDecl *PD : CD->parameters()) {
-        (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD);
+        Expr* Dummy;
+        (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), CD, PD, Dummy);
         S.DiscardCleanupsInEvaluationContext();
       }
     }
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -23,6 +23,7 @@
 #include "VarBypassDetector.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/CurrentSourceLocExprScope.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprOpenMP.h"
@@ -1622,7 +1623,8 @@
     CXXDefaultInitExprScope(CodeGenFunction &CGF, const CXXDefaultInitExpr *E)
         : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue),
           OldCXXThisAlignment(CGF.CXXThisAlignment),
-          SourceLocScope(E, CGF.CurSourceLocExprScope) {
+          SourceLocScope(SourceLocExpr::Context::FromDefaultInit(E),
+                         CGF.CurSourceLocExprScope) {
       CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer();
       CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment();
     }
@@ -1640,7 +1642,8 @@
 
   struct CXXDefaultArgExprScope : SourceLocExprScopeGuard {
     CXXDefaultArgExprScope(CodeGenFunction &CGF, const CXXDefaultArgExpr *E)
-        : SourceLocExprScopeGuard(E, CGF.CurSourceLocExprScope) {}
+        : SourceLocExprScopeGuard(SourceLocExpr::Context::FromDefaultArg(E),
+                                  CGF.CurSourceLocExprScope) {}
   };
 
   /// The scope of an ArrayInitLoopExpr. Within this scope, the value of the
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -646,7 +646,7 @@
   Value *VisitSourceLocExpr(SourceLocExpr *SLE) {
     auto &Ctx = CGF.getContext();
     APValue Evaluated =
-        SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getDefaultExpr());
+        SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getSLocs());
     return ConstantEmitter(CGF).emitAbstract(SLE->getLocation(), Evaluated,
                                              SLE->getType());
   }
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -15,6 +15,7 @@
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclOpenMP.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/LocInfoType.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/Module.h"
@@ -999,6 +1000,10 @@
              [=] { Visit(Node->getAPValueResult(), Node->getType()); });
 }
 
+void TextNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr* Node) {
+  AddChild("expr", [=] { Node->getExpr()->dumpColor(); });
+}
+
 void TextNodeDumper::VisitCallExpr(const CallExpr *Node) {
   if (Node->usesADL())
     OS << " adl";
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -7448,7 +7448,8 @@
     { return StmtVisitorTy::Visit(E->getReplacement()); }
   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
     TempVersionRAII RAII(*Info.CurrentCall);
-    SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
+    SourceLocExprScopeGuard Guard(SourceLocExpr::Context::FromDefaultArg(E),
+                                  Info.CurrentCall->CurSourceLocExprScope);
     return StmtVisitorTy::Visit(E->getExpr());
   }
   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
@@ -7456,7 +7457,8 @@
     // The initializer may not have been parsed yet, or might be erroneous.
     if (!E->getExpr())
       return Error(E);
-    SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
+    SourceLocExprScopeGuard Guard(SourceLocExpr::Context::FromDefaultInit(E),
+                                  Info.CurrentCall->CurSourceLocExprScope);
     return StmtVisitorTy::Visit(E->getExpr());
   }
 
@@ -8771,7 +8773,7 @@
   bool VisitSourceLocExpr(const SourceLocExpr *E) {
     assert(!E->isIntType() && "SourceLocExpr isn't a pointer type?");
     APValue LValResult = E->EvaluateInContext(
-        Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+        Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getSLocs());
     Result.setFrom(Info.Ctx, LValResult);
     return true;
   }
@@ -11122,7 +11124,7 @@
 
 bool IntExprEvaluator::VisitSourceLocExpr(const SourceLocExpr *E) {
   APValue Evaluated = E->EvaluateInContext(
-      Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
+      Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getSLocs());
   return Success(Evaluated, E);
 }
 
@@ -15146,14 +15148,18 @@
   return true;
 }
 
-bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
-                                  ConstantExprKind Kind) const {
+bool Expr::EvaluateAsConstantExpr(
+    EvalResult &Result, const ASTContext &Ctx, ConstantExprKind Kind,
+    CurrentSourceLocExprScope *SLocs) const {
   assert(!isValueDependent() &&
          "Expression evaluator can't be called on a dependent expression.");
 
   EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
   EvalInfo Info(Ctx, Result, EM);
   Info.InConstantContext = true;
+  if (SLocs) {
+    Info.BottomFrame.CurSourceLocExprScope = *SLocs;
+  }
 
   // The type of the object we're initializing is 'const T' for a class NTTP.
   QualType T = getType();
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -2168,20 +2168,27 @@
   llvm_unreachable("unexpected IdentKind!");
 }
 
+SourceLocExpr::Context
+SourceLocExpr::Context::FromDefaultArg(const CXXDefaultArgExpr *E) {
+  return {E->getUsedLocation(), E->getUsedContext()};
+}
+
+SourceLocExpr::Context
+SourceLocExpr::Context::FromDefaultInit(const CXXDefaultInitExpr *E) {
+  return {E->getUsedLocation(), E->getUsedContext()};
+}
+
 APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
-                                         const Expr *DefaultExpr) const {
+                                         llvm::Optional<Context> LocCtx) const {
   SourceLocation Loc;
   const DeclContext *Context;
-
-  std::tie(Loc,
-           Context) = [&]() -> std::pair<SourceLocation, const DeclContext *> {
-    if (auto *DIE = dyn_cast_or_null<CXXDefaultInitExpr>(DefaultExpr))
-      return {DIE->getUsedLocation(), DIE->getUsedContext()};
-    if (auto *DAE = dyn_cast_or_null<CXXDefaultArgExpr>(DefaultExpr))
-      return {DAE->getUsedLocation(), DAE->getUsedContext()};
-    return {this->getLocation(), this->getParentContext()};
-  }();
-
+  if (LocCtx) {
+    Loc = LocCtx->UsedLocation;
+    Context = LocCtx->UsedContext;
+  } else {
+    Loc = this->getLocation();
+    Context = this->getParentContext();
+  }
   PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
       Ctx.getSourceManager().getExpansionRange(Loc).getEnd());
 
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -7661,8 +7661,16 @@
       return std::move(Err);
   }
 
+  Expr* RewrittenArg = nullptr;
+  if (E->hasRewrittenArg()) {
+    auto ArgOrErr = import(E->getExpr());
+    if (!ArgOrErr) return ArgOrErr.takeError();
+    RewrittenArg = *ArgOrErr;
+  }
+
   return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
-                                   *ToParamOrErr, *UsedContextOrErr);
+                                   *ToParamOrErr, *UsedContextOrErr,
+                                   RewrittenArg);
 }
 
 ExpectedStmt
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -19,6 +19,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Availability.h"
 #include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/CurrentSourceLocExprScope.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/Expr.h"
@@ -1360,10 +1361,16 @@
                   ExpressionEvaluationContext::ImmediateFunctionContext &&
               InDiscardedStatement);
     }
+
+    bool isPotentiallyEvaluatedIfUsed() const {
+      return Context == ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed;
+    }
   };
 
   /// A stack of expression evaluation contexts.
   SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
+  /// Used to evaluate source locations.
+  CurrentSourceLocExprScope* OverridenSourceLocs = nullptr;
 
   /// Emit a warning for all pending noderef expressions that we recorded.
   void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec);
@@ -6126,7 +6133,7 @@
   /// Instantiate or parse a C++ default argument expression as necessary.
   /// Return true on error.
   bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
-                              ParmVarDecl *Param);
+                              ParmVarDecl *Param, Expr *&RewrittenArg);
 
   /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
   /// the default expr if needed.
@@ -9436,6 +9443,12 @@
     return ExprEvalContexts.back().isImmediateFunctionContext();
   }
 
+  bool isPotentiallyEvaluatedIfUsedContext() const {
+    assert(!ExprEvalContexts.empty() &&
+           "Must be in an expression evaluation context");
+    return ExprEvalContexts.back().isPotentiallyEvaluatedIfUsed();
+  }
+
   /// RAII class used to determine whether SFINAE has
   /// trapped any errors that occur during template argument
   /// deduction.
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -248,6 +248,7 @@
   void VisitCaseStmt(const CaseStmt *Node);
   void VisitCompoundStmt(const CompoundStmt *Node);
   void VisitConstantExpr(const ConstantExpr *Node);
+  void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
   void VisitCallExpr(const CallExpr *Node);
   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node);
   void VisitCastExpr(const CastExpr *Node);
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -686,6 +686,9 @@
 
     unsigned : NumExprBits;
 
+    /// Whether this CXXDefaultArgExpr rewrote its argument and stores a copy.
+    unsigned HasRewrittenArg : 1;
+
     /// The location where the default argument expression was used.
     SourceLocation Loc;
   };
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -1238,8 +1238,11 @@
 /// This wraps up a function call argument that was created from the
 /// corresponding parameter's default argument, when the call did not
 /// explicitly supply arguments for all of the parameters.
-class CXXDefaultArgExpr final : public Expr {
+class CXXDefaultArgExpr final
+    : public Expr,
+      private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> {
   friend class ASTStmtReader;
+  friend TrailingObjects;
 
   /// The parameter whose default is being used.
   ParmVarDecl *Param;
@@ -1247,8 +1250,13 @@
   /// The context where the default argument expression was used.
   DeclContext *UsedContext;
 
+  CXXDefaultArgExpr(EmptyShell Empty, bool HasRewrittenArg)
+      : Expr(CXXDefaultArgExprClass, Empty) {
+    CXXDefaultArgExprBits.HasRewrittenArg = HasRewrittenArg;
+  }
+
   CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *Param,
-                    DeclContext *UsedContext)
+                    DeclContext *UsedContext, Expr* RewrittenArg)
       : Expr(SC,
              Param->hasUnparsedDefaultArg()
                  ? Param->getType().getNonReferenceType()
@@ -1256,29 +1264,54 @@
              Param->getDefaultArg()->getValueKind(),
              Param->getDefaultArg()->getObjectKind()),
         Param(Param), UsedContext(UsedContext) {
+    CXXDefaultArgExprBits.HasRewrittenArg = !!RewrittenArg;
     CXXDefaultArgExprBits.Loc = Loc;
+    if (RewrittenArg)
+      *getTrailingObjects<Expr *>() = RewrittenArg;
     setDependence(computeDependence(this));
   }
 
+  size_t numTrailingObjects() const {
+    return CXXDefaultArgExprBits.HasRewrittenArg;
+  }
+
 public:
-  CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
+
+  static CXXDefaultArgExpr *CreateEmpty(const ASTContext &C, bool HasRewrittenArg) {
+    size_t Size = totalSizeToAlloc<Expr*>(HasRewrittenArg);
+    auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+    return new (Mem) CXXDefaultArgExpr(EmptyShell(), HasRewrittenArg);
+  }
 
   // \p Param is the parameter whose default argument is used by this
   // expression.
   static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
                                    ParmVarDecl *Param,
-                                   DeclContext *UsedContext) {
-    return new (C)
-        CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, UsedContext);
+                                   DeclContext *UsedContext,
+                                   Expr* RewrittenArg = nullptr) {
+    size_t Size = totalSizeToAlloc<Expr*>(RewrittenArg != nullptr);
+    auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+    return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
+                                       UsedContext, RewrittenArg);
   }
 
+  bool hasRewrittenArg() const { return CXXDefaultArgExprBits.HasRewrittenArg; }
+
   // Retrieve the parameter that the argument was created from.
   const ParmVarDecl *getParam() const { return Param; }
   ParmVarDecl *getParam() { return Param; }
 
   // Retrieve the actual argument to the function call.
-  const Expr *getExpr() const { return getParam()->getDefaultArg(); }
-  Expr *getExpr() { return getParam()->getDefaultArg(); }
+  const Expr *getExpr() const {
+    if (CXXDefaultArgExprBits.HasRewrittenArg)
+      return *getTrailingObjects<Expr *>();
+    return getParam()->getDefaultArg();
+  }
+  Expr *getExpr() {
+    if (CXXDefaultArgExprBits.HasRewrittenArg)
+      return *getTrailingObjects<Expr *>();
+    return getParam()->getDefaultArg();
+  }
 
   const DeclContext *getUsedContext() const { return UsedContext; }
   DeclContext *getUsedContext() { return UsedContext; }
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -18,6 +18,7 @@
 #include "clang/AST/ComputeDependence.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclAccessPair.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DependenceFlags.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/Stmt.h"
@@ -55,6 +56,7 @@
   class StringLiteral;
   class TargetInfo;
   class ValueDecl;
+  class CurrentSourceLocExprScope;
 
 /// A simple array of base specifiers.
 typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
@@ -732,9 +734,9 @@
 
   /// Evaluate an expression that is required to be a constant expression. Does
   /// not check the syntactic constraints for C and C++98 constant expressions.
-  bool EvaluateAsConstantExpr(
-      EvalResult &Result, const ASTContext &Ctx,
-      ConstantExprKind Kind = ConstantExprKind::Normal) const;
+  bool EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
+                              ConstantExprKind Kind = ConstantExprKind::Normal,
+                              CurrentSourceLocExprScope *SLocs = nullptr) const;
 
   /// If the current Expr is a pointer, this will try to statically
   /// determine the number of bytes available where the pointer is pointing.
@@ -4689,10 +4691,18 @@
   /// Build an empty call expression.
   explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
 
+  struct Context {
+    SourceLocation UsedLocation;
+    const DeclContext *UsedContext = nullptr;
+
+    static Context FromDefaultArg(const CXXDefaultArgExpr* E);
+    static Context FromDefaultInit(const CXXDefaultInitExpr* E);
+  };
+
   /// Return the result of evaluating this SourceLocExpr in the specified
   /// (and possibly null) default argument or initialization context.
   APValue EvaluateInContext(const ASTContext &Ctx,
-                            const Expr *DefaultExpr) const;
+                            llvm::Optional<Context> LocCtx) const;
 
   /// Return a string representing the name of the specific builtin function.
   StringRef getBuiltinStr() const;
Index: clang/include/clang/AST/CurrentSourceLocExprScope.h
===================================================================
--- clang/include/clang/AST/CurrentSourceLocExprScope.h
+++ clang/include/clang/AST/CurrentSourceLocExprScope.h
@@ -14,6 +14,8 @@
 #ifndef LLVM_CLANG_AST_CURRENTSOURCELOCEXPRSCOPE_H
 #define LLVM_CLANG_AST_CURRENTSOURCELOCEXPRSCOPE_H
 
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/Optional.h"
 #include <cassert>
 
 namespace clang {
@@ -23,8 +25,9 @@
 /// value of the source location builtins (ex. __builtin_LINE), including the
 /// context of default argument and default initializer expressions.
 class CurrentSourceLocExprScope {
-  /// The CXXDefaultArgExpr or CXXDefaultInitExpr we're currently evaluating.
-  const Expr *DefaultExpr = nullptr;
+  /// The source locations coming from CXXDefaultArgExpr or CXXDefaultInitExpr
+  /// we're currently evaluating.
+  llvm::Optional<SourceLocExpr::Context> Context;
 
 public:
   /// A RAII style scope guard used for tracking the current source
@@ -32,27 +35,23 @@
   /// (ex. __builtin_LINE).
   class SourceLocExprScopeGuard;
 
-  const Expr *getDefaultExpr() const { return DefaultExpr; }
+  llvm::Optional<SourceLocExpr::Context> getSLocs() const { return Context; }
 
   explicit CurrentSourceLocExprScope() = default;
 
 private:
-  explicit CurrentSourceLocExprScope(const Expr *DefaultExpr)
-      : DefaultExpr(DefaultExpr) {}
-
-  CurrentSourceLocExprScope(CurrentSourceLocExprScope const &) = default;
-  CurrentSourceLocExprScope &
-  operator=(CurrentSourceLocExprScope const &) = default;
+  explicit CurrentSourceLocExprScope(
+      llvm::Optional<SourceLocExpr::Context> Context)
+      : Context(std::move(Context)) {}
 };
 
 class CurrentSourceLocExprScope::SourceLocExprScopeGuard {
 public:
-  SourceLocExprScopeGuard(const Expr *DefaultExpr,
+  SourceLocExprScopeGuard(SourceLocExpr::Context Context,
                           CurrentSourceLocExprScope &Current)
       : Current(Current), OldVal(Current), Enable(false) {
-    assert(DefaultExpr && "the new scope should not be empty");
-    if ((Enable = (Current.getDefaultExpr() == nullptr)))
-      Current = CurrentSourceLocExprScope(DefaultExpr);
+    if ((Enable = (!Current.getSLocs().has_value())))
+      Current = CurrentSourceLocExprScope(Context);
   }
 
   ~SourceLocExprScopeGuard() {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to