ilya-biryukov created this revision.
ilya-biryukov added a reviewer: jyknight.
Herald added a project: All.
ilya-biryukov requested review of this revision.
Herald added a project: clang.

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.
This affects correctness of `std::source_location`.

Fixes #56379.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D129488

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaExpr.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,59 @@
+// 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; }
+
+#line 700 "CheckDefaultArg.h"
+constexpr SL l = get_sl();
+static_assert(l.line() == 700);
+static_assert(is_equal(l.file(), "CheckDefaultArg.h"));
+
+void test() {
+  static_assert(is_equal(get_sl().function(), __PRETTY_FUNCTION__));
+  static_assert(get_sl().line() ==  __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/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -17500,7 +17500,8 @@
       /*IsImmediateInvocation*/ true);
   /// Value-dependent constant expressions should not be immediately
   /// evaluated until they are instantiated.
-  if (!Res->isValueDependent())
+  /// Default arguments must be evaluated in the context of their call.
+  if (!Res->isValueDependent() && !isPotentiallyEvaluatedIfUsedContext())
     ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1359,6 +1359,10 @@
                   ExpressionEvaluationContext::ImmediateFunctionContext &&
               InDiscardedStatement);
     }
+
+    bool isPotentiallyEvaluatedIfUsed() const {
+      return Context == ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed;
+    }
   };
 
   /// A stack of expression evaluation contexts.
@@ -9406,6 +9410,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.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to