EricWF created this revision.

This patch implements the source location builtins `__builtin_LINE(), 
`__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These 
builtins are needed to implement 
[`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, 
and Clangs behavior is intended to match as closely as possible.


https://reviews.llvm.org/D37035

Files:
  docs/LanguageExtensions.rst
  include/clang/AST/Expr.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Basic/TokenKinds.def
  include/clang/Sema/Sema.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprConstant.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/Parse/ParseExpr.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CodeGenCXX/builtin_FUNCTION.cpp
  test/CodeGenCXX/builtin_LINE.cpp
  test/CodeGenCXX/debug-info-line.cpp
  test/Parser/builtin_source_location.c
  test/Sema/source_location.c
  test/SemaCXX/Inputs/source-location-file.h
  test/SemaCXX/source_location.cpp

Index: test/SemaCXX/source_location.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/source_location.cpp
@@ -0,0 +1,425 @@
+// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify %s
+// expected-no-diagnostics
+
+#define assert(...) ((__VA_ARGS__) ? ((void)0) : throw 42)
+#define CURRENT_FROM_MACRO() SL::current()
+#define FORWARD(...) __VA_ARGS__
+
+namespace std {
+namespace experimental {
+struct source_location {
+private:
+  unsigned int __m_line = 0;
+  unsigned int __m_col = 0;
+  const char *__m_file = nullptr;
+  const char *__m_func = nullptr;
+public:
+  static constexpr source_location current(
+      const char *__file = __builtin_FILE(),
+      const char *__func = __builtin_FUNCTION(),
+      unsigned int __line = __builtin_LINE(),
+      unsigned int __col = __builtin_COLUMN()) noexcept {
+    source_location __loc;
+    __loc.__m_line = __line;
+    __loc.__m_col = __col;
+    __loc.__m_file = __file;
+    __loc.__m_func = __func;
+    return __loc;
+  }
+  constexpr source_location() = default;
+  constexpr source_location(source_location const &) = default;
+  constexpr unsigned int line() const noexcept { return __m_line; }
+  constexpr unsigned int column() const noexcept { return __m_col; }
+  constexpr const char *file() const noexcept { return __m_file; }
+  constexpr const char *function() const noexcept { return __m_func; }
+};
+} // namespace experimental
+} // namespace std
+
+using SL = std::experimental::source_location;
+
+#include "Inputs/source-location-file.h"
+namespace SLF = source_location_file;
+
+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;
+}
+
+template <class T>
+constexpr T identity(T t) {
+  return t;
+}
+
+template <class T, class U>
+struct Pair {
+  T first;
+  U second;
+};
+
+template <class T, class U>
+constexpr bool is_same = false;
+template <class T>
+constexpr bool is_same<T, T> = true;
+
+// test types
+static_assert(is_same<decltype(__builtin_LINE()), unsigned>);
+static_assert(is_same<decltype(__builtin_COLUMN()), unsigned>);
+static_assert(is_same<decltype(__builtin_FILE()), const char *>);
+static_assert(is_same<decltype(__builtin_FUNCTION()), const char *>);
+
+// test noexcept
+static_assert(noexcept(__builtin_LINE()));
+static_assert(noexcept(__builtin_COLUMN()));
+static_assert(noexcept(__builtin_FILE()));
+static_assert(noexcept(__builtin_FUNCTION()));
+
+//===----------------------------------------------------------------------===//
+//                            __builtin_LINE()
+//===----------------------------------------------------------------------===//
+
+namespace test_line {
+
+static_assert(SL::current().line() == __LINE__);
+static_assert(SL::current().line() == CURRENT_FROM_MACRO().line());
+
+static constexpr SL GlobalS = SL::current();
+
+static_assert(GlobalS.line() == __LINE__ - 2);
+
+// clang-format off
+constexpr bool test_line_fn() {
+  constexpr SL S = SL::current();
+  static_assert(S.line() == (__LINE__ - 1), "");
+  // The start of the call expression to `current()` begins at the token `SL`
+  constexpr int ExpectLine = __LINE__ + 3;
+  constexpr SL S2
+  =
+  SL // Call expression starts here
+  ::
+  current
+  (
+
+  )
+  ;
+  static_assert(S2.line() == ExpectLine, "");
+
+  static_assert(
+          FORWARD(
+             __builtin_LINE
+            (
+            )
+          )
+    == __LINE__ - 1, "");
+  static_assert(\
+\
+  __builtin_LINE()\
+\
+  == __LINE__ - 2, "");
+  static_assert(\
+          _\
+_builtin_LINE()
+          == __LINE__ - 2, "");
+
+  return true;
+}
+// clang-format on
+static_assert(test_line_fn());
+
+static_assert(__builtin_LINE() == __LINE__, "");
+
+constexpr int baz() { return 101; }
+
+constexpr int test_line_fn_simple(int z = baz(), int x = __builtin_LINE()) {
+  return x;
+}
+void bar() {
+  static_assert(test_line_fn_simple() == __LINE__, "");
+  static_assert(test_line_fn_simple() == __LINE__, "");
+}
+
+template <class T>
+constexpr bool test_line_fn_template(T Expect, int L = __builtin_LINE()) {
+  return Expect == L;
+}
+static_assert(test_line_fn_template(__LINE__));
+
+struct InMemInit {
+  constexpr bool check(int expect) const {
+    return info.line() == expect;
+  }
+  SL info = SL::current();
+  InMemInit() = default;
+  constexpr InMemInit(int) {}
+};
+static_assert(InMemInit{}.check(__LINE__ - 3), "");
+static_assert(InMemInit{42}.check(__LINE__ - 3), "");
+
+template <class T, class U = SL>
+struct InMemInitTemplate {
+  constexpr bool check(int expect) const {
+    return info.line() == expect;
+  }
+  U info = U::current();
+  InMemInitTemplate() = default;
+  constexpr InMemInitTemplate(T) {}
+  constexpr InMemInitTemplate(T, T) : info(U::current()) {}
+  template <class V = U> constexpr InMemInitTemplate(T, T, T, V info = U::current())
+      : info(info) {}
+};
+void test_mem_init_template() {
+  constexpr int line_offset = 8;
+  static_assert(InMemInitTemplate<int>{}.check(__LINE__ - line_offset), "");
+  static_assert(InMemInitTemplate<unsigned>{42}.check(__LINE__ - line_offset), "");
+  static_assert(InMemInitTemplate<unsigned>{42, 42}.check(__LINE__ - line_offset), "");
+  static_assert(InMemInitTemplate<unsigned>{42, 42, 42}.check(__LINE__), "");
+}
+
+struct AggInit {
+  int x;
+  int y = __builtin_LINE();
+  constexpr bool check(int expect) const {
+    return y == expect;
+  }
+};
+constexpr AggInit AI{42};
+static_assert(AI.check(__LINE__ - 1), "");
+
+template <class T, class U = SL>
+struct AggInitTemplate {
+  constexpr bool check(int expect) const {
+    return expect == info.line();
+  }
+  T x;
+  U info = U::current();
+};
+
+template <class T, class U = SL>
+constexpr U test_fn_template(T, U u = U::current()) {
+  return u;
+}
+void fn_template_tests() {
+  static_assert(test_fn_template(42).line() == __LINE__, "");
+}
+
+struct TestMethodTemplate {
+  template <class T, class U = SL, class U2 = SL>
+  constexpr U get(T, U u = U::current(), U2 u2 = identity(U2::current())) const {
+    assert(u.line() == u2.line());
+    return u;
+  }
+};
+void method_template_tests() {
+  static_assert(TestMethodTemplate{}.get(42).line() == __LINE__, "");
+}
+
+struct InStaticInit {
+  static constexpr int LINE = __LINE__;
+  static constexpr const int x1 = __builtin_LINE();
+  static constexpr const int x2 = identity(__builtin_LINE());
+  static const int x3;
+  const int x4 = __builtin_LINE();
+  int x5 = __builtin_LINE();
+};
+const int InStaticInit::x3 = __builtin_LINE();
+static_assert(InStaticInit::x1 == InStaticInit::LINE + 1, "");
+static_assert(InStaticInit::x2 == InStaticInit::LINE + 2, "");
+
+template <class T, int N = __builtin_LINE(), int Expect = -1>
+constexpr void check_fn_template_param(T) {
+  constexpr int RealExpect = Expect == -1 ? __LINE__ - 2 : Expect;
+  static_assert(N == RealExpect);
+}
+template void check_fn_template_param(int);
+template void check_fn_template_param<long, 42, 42>(long);
+
+} // namespace test_line
+
+//===----------------------------------------------------------------------===//
+//                            __builtin_FILE()
+//===----------------------------------------------------------------------===//
+
+namespace test_file {
+constexpr const char *test_file_simple(const char *__f = __builtin_FILE()) {
+  return __f;
+}
+void test_function() {
+  static_assert(is_equal(test_file_simple(), __FILE__));
+  static_assert(is_equal(SLF::test_function().file(), __FILE__), "");
+  static_assert(is_equal(SLF::test_function_template(42).file(), __FILE__), "");
+
+  static_assert(is_equal(SLF::test_function_indirect().file(), SLF::global_info.file()), "");
+  static_assert(is_equal(SLF::test_function_template_indirect(42).file(), SLF::global_info.file()), "");
+
+  static_assert(test_file_simple() != nullptr);
+  static_assert(!is_equal(test_file_simple(), "source_location.cpp"));
+}
+void test_class() {
+  using SLF::TestClass;
+  constexpr TestClass Default;
+  constexpr TestClass InParam{42};
+  constexpr TestClass Template{42, 42};
+  static_assert(is_equal(Default.info.file(), SLF::FILE), "");
+  static_assert(is_equal(InParam.info.file(), SLF::FILE), "");
+  static_assert(is_equal(InParam.ctor_info.file(), __FILE__), "");
+}
+
+void test_aggr_class() {
+  using Agg = SLF::AggrClass<>;
+  constexpr Agg Default{};
+  constexpr Agg InitOne{42};
+  static_assert(is_equal(Default.init_info.file(), __FILE__), "");
+  static_assert(is_equal(InitOne.init_info.file(), __FILE__), "");
+}
+
+} // namespace test_file
+
+//===----------------------------------------------------------------------===//
+//                            __builtin_FUNCTION()
+//===----------------------------------------------------------------------===//
+
+namespace test_func {
+
+constexpr const char *test_func_simple(const char *__f = __builtin_FUNCTION()) {
+  return __f;
+}
+constexpr const char *get_function() {
+  return __func__;
+}
+constexpr bool test_function() {
+  return is_equal(__func__, test_func_simple()) &&
+         !is_equal(get_function(), test_func_simple());
+}
+static_assert(test_function());
+
+template <class T, class U = SL>
+constexpr Pair<U, U> test_func_template(T, U u = U::current()) {
+  static_assert(is_equal(__func__, U::current().function()));
+  return {u, U::current()};
+}
+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__), "");
+}
+template void func_template_tests<int>();
+
+template <class = int, class T = SL>
+struct TestCtor {
+  T info = T::current();
+  T ctor_info;
+  TestCtor() = default;
+  template <class U = SL>
+  constexpr TestCtor(int, U u = U::current()) : ctor_info(u) {}
+};
+void ctor_tests() {
+  constexpr TestCtor<> Default;
+  constexpr TestCtor<> Template{42};
+  static_assert(!is_equal(Default.info.function(), __func__));
+  static_assert(is_equal(Default.info.function(), "TestCtor"));
+  static_assert(is_equal(Template.info.function(), "TestCtor"));
+  static_assert(is_equal(Template.ctor_info.function(), __func__));
+}
+
+constexpr SL global_sl = SL::current();
+static_assert(is_equal(global_sl.function(), ""));
+
+} // namespace test_func
+
+//===----------------------------------------------------------------------===//
+//                            __builtin_COLUMN()
+//===----------------------------------------------------------------------===//
+
+namespace test_column {
+
+// clang-format off
+constexpr bool test_column_fn() {
+  constexpr SL S = SL::current();
+  static_assert(S.line() == (__LINE__ - 1), "");
+  constexpr int Indent = 4;
+  {
+    // The start of the call expression to `current()` begins at the token `SL`
+    constexpr int ExpectCol = Indent + 3;
+    constexpr SL S2
+     =
+      SL // Call expression starts here
+        ::
+          current
+                 (
+
+                  )
+                   ;
+    static_assert(S2.column() == ExpectCol, "");
+  }
+  {
+    constexpr int ExpectCol = 2;
+    constexpr int C =
+ __builtin_COLUMN // Expect call expression to start here
+      ();
+    static_assert(C == ExpectCol);
+  }
+  return true;
+}
+
+static_assert(test_column_fn());
+
+// Test that the column matches the start of the call expression 'SL::current()'
+static_assert(SL::current().column() == __builtin_strlen("static_assert(S"));
+struct TestClass {
+  int x = __builtin_COLUMN();
+   TestClass() = default; /* indented to 3 spaces for testing */
+  constexpr TestClass(int, int o = __builtin_COLUMN()) : x(o) {}
+};
+struct TestAggClass {
+  int x = __builtin_COLUMN();
+};
+constexpr bool test_class() {
+
+  auto check = [](int V, const char* S, int indent = 4) {
+    assert(V == (__builtin_strlen(S) + indent));
+  };
+  {
+    TestClass t{};
+    check(t.x, "   T", 0); // Start of default constructor decl.
+  }
+  {
+    TestClass t1
+            {42};
+    check(t1.x, "TestClass t"); // Start of variable being constructed.
+  }
+  {
+    TestAggClass t  {};
+    check(t.x, "TestAggClass t  {");
+  }
+  {
+    TestAggClass t = {};
+    check(t.x, "TestAggClass t = {");
+  }
+  return true;
+}
+static_assert(test_class());
+// clang-format on
+} // namespace test_column
+
+// Test [reflection.src_loc.creation]p2
+//  >  The value should be affected by #line (C++14 16.4) in the same manner as
+//  >  for __LINE__ and __FILE__.
+namespace test_pragma_line {
+constexpr int StartLine = 42;
+#line 42
+static_assert(__builtin_LINE() == StartLine);
+static_assert(__builtin_LINE() == StartLine + 1);
+static_assert(SL::current().line() == StartLine + 2);
+#line 44 "test_file.c"
+static_assert(is_equal("test_file.c", __FILE__));
+static_assert(is_equal("test_file.c", __builtin_FILE()));
+static_assert(is_equal("test_file.c", SL::current().file()));
+static_assert(is_equal("test_file.c", SLF::test_function().file()));
+static_assert(is_equal(SLF::FILE, SLF::test_function_indirect().file()));
+} // end namespace test_pragma_line
Index: test/SemaCXX/Inputs/source-location-file.h
===================================================================
--- /dev/null
+++ test/SemaCXX/Inputs/source-location-file.h
@@ -0,0 +1,43 @@
+
+// NOTE: source_location.cpp must include this file after defining
+// std::source_location.
+namespace source_location_file {
+
+constexpr const char *FILE = __FILE__;
+constexpr SL global_info = SL::current();
+
+constexpr SL test_function(SL v = SL::current()) {
+  return v;
+}
+
+constexpr SL test_function_indirect() {
+  return test_function();
+}
+
+template <class T, class U = SL>
+constexpr U test_function_template(T, U u = U::current()) {
+  return u;
+}
+
+template <class T, class U = SL>
+constexpr U test_function_template_indirect(T t) {
+  return test_function_template(t);
+}
+
+struct TestClass {
+  SL info = SL::current();
+  SL ctor_info;
+  TestClass() = default;
+  constexpr TestClass(int, SL cinfo = SL::current()) : ctor_info(cinfo) {}
+  template <class T, class U = SL>
+  constexpr TestClass(int, T, U u = U::current()) : ctor_info(u) {}
+};
+
+template <class T = SL>
+struct AggrClass {
+  int x;
+  T info;
+  T init_info = T::current();
+};
+
+} // namespace source_location_file
Index: test/Sema/source_location.c
===================================================================
--- /dev/null
+++ test/Sema/source_location.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c90 -fconst-strings -DCONST_STRINGS -verify %s
+// RUN: %clang_cc1 -std=c90 -verify %s
+
+// expected-no-diagnostics
+
+#define IsEqual(L, R) (__builtin_strcmp(L, R) == 0)
+
+const char *const FILE = __builtin_FILE();
+const char *const FUNC = __builtin_FUNCTION();
+const unsigned LINE = __builtin_LINE();
+const unsigned COL = __builtin_COLUMN();
+
+#ifndef CONST_STRINGS
+char *const NCFILE = __builtin_FILE();
+char *const NCFUNC = __builtin_FUNCTION();
+#endif
+
+#ifdef CONST_STRINGS
+_Static_assert(IsEqual(__builtin_FILE(), __FILE__), "");
+_Static_assert(__builtin_LINE() == __LINE__, "");
+_Static_assert(IsEqual("", __builtin_FUNCTION()), "");
+
+#line 42 "my_file.c"
+_Static_assert(__builtin_LINE() == 42, "");
+_Static_assert(IsEqual(__builtin_FILE(), "my_file.c"), "");
+
+_Static_assert(__builtin_COLUMN() == __builtin_strlen("_Static_assert(_"), "");
+
+void foo() {
+  _Static_assert(IsEqual(__builtin_FUNCTION(), "foo"), "");
+}
+#endif // CONST_STRINGS
Index: test/Parser/builtin_source_location.c
===================================================================
--- /dev/null
+++ test/Parser/builtin_source_location.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int main() {
+  int line = __builtin_LINE();
+  __builtin_LINE(42); // expected-error {{expected ')'}}
+  __builtin_LINE(double); // expected-error {{expected ')'}}
+
+  int column = __builtin_COLUMN();
+  __builtin_COLUMN(42); // expected-error {{expected ')'}}
+  __builtin_COLUMN(double); // expected-error {{expected ')'}}
+
+  const char *func = __builtin_FUNCTION();
+  __builtin_FUNCTION(42); // expected-error {{expected ')'}}
+  __builtin_FUNCTION(double); // expected-error {{expected ')'}}
+
+  const char *file = __builtin_FILE();
+  __builtin_FILE(42); // expected-error {{expected ')'}}
+  __builtin_FILE(double); // expected-error {{expected ')'}}
+}
Index: test/CodeGenCXX/debug-info-line.cpp
===================================================================
--- test/CodeGenCXX/debug-info-line.cpp
+++ test/CodeGenCXX/debug-info-line.cpp
@@ -291,6 +291,13 @@
   f24_a();
 }
 
+// CHECK-LABEL: define
+void f25_a(int x = __builtin_LINE()) {}
+void f25() {
+  // CHECK: call void @_Z5f25_ai(i32 2700)
+#line 2700
+  f25_a();
+}
 // CHECK: [[DBG_F1]] = !DILocation(line: 100,
 // CHECK: [[DBG_FOO_VALUE]] = !DILocation(line: 200,
 // CHECK: [[DBG_FOO_REF]] = !DILocation(line: 202,
Index: test/CodeGenCXX/builtin_LINE.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/builtin_LINE.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -std=c++1z -fblocks %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+
+extern "C" int sink;
+struct Tag1 {};
+struct Tag2 {};
+struct Tag3 {};
+struct Tag4 {};
+
+constexpr int get_line_constexpr(int l = __builtin_LINE()) {
+  return l;
+}
+
+// CHECK: @global_one = global i32 [[@LINE+1]], align 4
+int global_one = __builtin_LINE();
+// CHECK-NEXT: @global_two = global i32 [[@LINE+1]], align 4
+int global_two = get_line_constexpr();
+
+struct InClassInit {
+  int Init = __builtin_LINE();
+  InClassInit() = default;
+  constexpr InClassInit(Tag1, int l = __builtin_LINE()) : Init(l) {}
+  constexpr InClassInit(Tag2) : Init(__builtin_LINE()) {}
+  InClassInit(Tag3, int l = __builtin_LINE()) : Init(l) {}
+  InClassInit(Tag4) : Init(__builtin_LINE()) {}
+
+  static void test_class();
+};
+// CHECK-LABEL: define void @_ZN11InClassInit10test_classEv()
+void InClassInit::test_class() {
+  // CHECK: call void @_ZN11InClassInitC1Ev(%struct.InClassInit* %test_one)
+  InClassInit test_one;
+  // CHECK-NEXT: call void @_ZN11InClassInitC1E4Tag1i(%struct.InClassInit* %test_two, i32 [[@LINE+1]])
+  InClassInit test_two{Tag1{}};
+  // CHECK-NEXT: call void @_ZN11InClassInitC1E4Tag2(%struct.InClassInit* %test_three)
+  InClassInit test_three{Tag2{}};
+  // CHECK-NEXT: call void @_ZN11InClassInitC1E4Tag3i(%struct.InClassInit* %test_four, i32 [[@LINE+1]])
+  InClassInit test_four(Tag3{});
+  // CHECK-NEXT: call void @_ZN11InClassInitC1E4Tag4(%struct.InClassInit* %test_five)
+  InClassInit test_five{Tag4{}};
+}
+
+int get_line(int l = __builtin_LINE()) {
+  return l;
+}
+
+// CHECK-LABEL: define void @_Z13get_line_testv()
+void get_line_test() {
+  // CHECK: %[[CALL:.+]] = call i32 @_Z8get_linei(i32 [[@LINE+2]])
+  // CHECK-NEXT: store i32 %[[CALL]], i32* @sink, align 4
+  sink = get_line();
+  // CHECK-NEXT:  store i32 [[@LINE+1]], i32* @sink, align 4
+  sink = __builtin_LINE();
+}
Index: test/CodeGenCXX/builtin_FUNCTION.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/builtin_FUNCTION.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++1z -fblocks %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
+
+namespace test_func {
+
+constexpr const char *test_default_arg(const char *f = __builtin_FUNCTION()) {
+  return f;
+}
+// CHECK: @[[EMPTY_STR:.+]] = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
+
+// CHECK: @_ZN9test_func6globalE = global i8* getelementptr inbounds ([1 x i8], [1 x i8]* @[[EMPTY_STR]], i32 0, i32 0), align 8
+const char *global = test_default_arg();
+
+// CHECK: @_ZN9test_func10global_twoE = global i8* getelementptr inbounds ([1 x i8], [1 x i8]* @[[EMPTY_STR]], i32 0, i32 0), align 8
+const char *global_two = __builtin_FUNCTION();
+
+// CHECK: @[[STR_ONE:.+]] = private unnamed_addr constant [14 x i8] c"test_func_one\00", align 1
+// CHECK: @[[STR_TWO:.+]] = private unnamed_addr constant [14 x i8] c"test_func_two\00", align 1
+// CHECK: @[[STR_THREE:.+]] = private unnamed_addr constant [20 x i8] c"do_default_arg_test\00", align 1
+
+// CHECK: define i8* @_ZN9test_func13test_func_oneEv()
+// CHECK: ret i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[STR_ONE]], i32 0, i32 0)
+const char *test_func_one() {
+  return __builtin_FUNCTION();
+}
+
+// CHECK: define i8* @_ZN9test_func13test_func_twoEv()
+// CHECK: ret i8* getelementptr inbounds ([14 x i8], [14 x i8]* @[[STR_TWO]], i32 0, i32 0)
+const char *test_func_two() {
+  return __builtin_FUNCTION();
+}
+
+// CHECK: define void @_ZN9test_func19do_default_arg_testEv()
+// CHECK: %call = call i8* @_ZN9test_func16test_default_argEPKc(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @[[STR_THREE]], i32 0, i32 0))
+void do_default_arg_test() {
+  test_default_arg();
+}
+
+template <class>
+void test_template(const char *f = __builtin_FUNCTION()) {
+  (void)__builtin_FUNCTION();
+}
+void do_template_test() {
+  test_template<int>();
+}
+} // namespace test_func
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1021,6 +1021,7 @@
     case Stmt::NoInitExprClass:
     case Stmt::SizeOfPackExprClass:
     case Stmt::StringLiteralClass:
+    case Stmt::SourceLocExprClass:
     case Stmt::ObjCStringLiteralClass:
     case Stmt::CXXPseudoDestructorExprClass:
     case Stmt::SubstNonTypeTemplateParmExprClass:
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -843,6 +843,15 @@
   Code = serialization::EXPR_VA_ARG;
 }
 
+void ASTStmtWriter::VisitSourceLocExpr(SourceLocExpr *E) {
+  VisitExpr(E);
+  Record.AddStmt(E->getSubExpr());
+  Record.AddSourceLocation(E->getLocStart());
+  Record.AddSourceLocation(E->getLocEnd());
+  Record.push_back(E->getIdentType());
+  Code = serialization::EXPR_SOURCE_LOC;
+}
+
 void ASTStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
   VisitExpr(E);
   Record.AddSourceLocation(E->getAmpAmpLoc());
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -862,6 +862,14 @@
   E->setIsMicrosoftABI(Record.readInt());
 }
 
+void ASTStmtReader::VisitSourceLocExpr(SourceLocExpr *E) {
+  VisitExpr(E);
+  E->setSubExpr(Record.readSubExpr());
+  E->setLocStart(ReadSourceLocation());
+  E->setLocEnd(ReadSourceLocation());
+  E->setIdentType(static_cast<SourceLocExpr::IdentType>(Record.readInt()));
+}
+
 void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
   VisitExpr(E);
   E->setAmpAmpLoc(ReadSourceLocation());
@@ -3342,6 +3350,10 @@
       S = new (Context) VAArgExpr(Empty);
       break;
 
+    case EXPR_SOURCE_LOC:
+      S = new (Context) SourceLocExpr(Empty);
+      break;
+
     case EXPR_ADDR_LABEL:
       S = new (Context) AddrLabelExpr(Empty);
       break;
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -2928,6 +2928,18 @@
                                   RParenLoc, Length, PartialArgs);
   }
 
+  /// \brief Build a new expression representing a call to a source location
+  ///  builtin.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildSourceLocExpr(SourceLocExpr::IdentType Type,
+                                  SourceLocation BuiltinLoc,
+                                  SourceLocation RPLoc,
+                                  Expr *SubExpr = nullptr) {
+    return getSema().BuildSourceLocExpr(Type, BuiltinLoc, RPLoc, SubExpr);
+  }
+
   /// \brief Build a new Objective-C boxed expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -9792,6 +9804,22 @@
   return getDerived().TransformCallExpr(E);
 }
 
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformSourceLocExpr(SourceLocExpr *E) {
+  Expr *SubExpr = E->getSubExpr();
+  if (SubExpr) {
+    ExprResult Res = getDerived().TransformExpr(SubExpr);
+    if (Res.isInvalid())
+      return ExprError();
+    SubExpr = Res.get();
+  }
+  bool SubExprChanged = SubExpr && SubExpr != E->getSubExpr()->IgnoreImpCasts();
+  if (!getDerived().AlwaysRebuild() && !SubExprChanged)
+    return E;
+  return getDerived().RebuildSourceLocExpr(E->getIdentType(), E->getLocStart(),
+                                           E->getLocEnd(), SubExpr);
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -554,7 +554,23 @@
     //   members in the aggregate, then each member not explicitly initialized
     //   shall be initialized from its brace-or-equal-initializer [...]
     if (Field->hasInClassInitializer()) {
-      ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
+      if (SemaRef.CheckCXXDefaultInitExpr(Loc, Field)) {
+        hadError = true;
+        return;
+      }
+      ExprResult DIE(/*Invalid*/ true);
+      if (SemaRef.CheckCXXDefaultInitExpr(Loc, Field)) {
+        /* nothing todo */
+      } else if (SourceLocExpr::containsSourceLocExpr(
+                     Field->getInClassInitializer())) {
+        DIE = SemaRef.TransformInitContainingSourceLocExpressions(
+            Field->getInClassInitializer(), ILE->getLocStart());
+        if (!DIE.isInvalid())
+          DIE = SemaRef.PerformCopyInitialization(
+              MemberEntity, SourceLocation(), DIE.get(), true, true);
+      } else
+        DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
+
       if (DIE.isInvalid()) {
         hadError = true;
         return;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3010,19 +3010,9 @@
 ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
                                      PredefinedExpr::IdentType IT) {
   // Pick the current block, lambda, captured statement or function.
-  Decl *currentDecl = nullptr;
-  if (const BlockScopeInfo *BSI = getCurBlock())
-    currentDecl = BSI->TheDecl;
-  else if (const LambdaScopeInfo *LSI = getCurLambda())
-    currentDecl = LSI->CallOperator;
-  else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion())
-    currentDecl = CSI->TheCapturedDecl;
-  else
-    currentDecl = getCurFunctionOrMethodDecl();
-
-  if (!currentDecl) {
+  Decl *currentDecl = getDeclForCurContext();
+  if (currentDecl == Context.getTranslationUnitDecl()) {
     Diag(Loc, diag::ext_predef_outside_function);
-    currentDecl = Context.getTranslationUnitDecl();
   }
 
   QualType ResTy;
@@ -4849,12 +4839,24 @@
       Arg = ArgE.getAs<Expr>();
     } else {
       assert(Param && "can't use default arguments without a known callee");
-
-      ExprResult ArgExpr =
-        BuildCXXDefaultArgExpr(CallLoc, FDecl, Param);
+      if (CheckCXXDefaultArgExpr(CallLoc, FDecl, Param))
+        return true;
+      ExprResult ArgExpr = ExprError();
+      if (SourceLocExpr::containsSourceLocExpr(Param->getDefaultArg())) {
+        ArgExpr = TransformInitContainingSourceLocExpressions(
+            Param->getDefaultArg(), CallLoc);
+        if (ArgExpr.isInvalid())
+          return true;
+        InitializedEntity Entity =  InitializedEntity::InitializeParameter(Context,
+                                                                           Param,
+                                                         ProtoArgType);
+        ArgExpr = PerformCopyInitialization(
+          Entity, SourceLocation(), ArgExpr.get(), IsListInitialization, AllowExplicit);
+      } else {
+        ArgExpr = CXXDefaultArgExpr::Create(Context, CallLoc, Param);
+      }
       if (ArgExpr.isInvalid())
         return true;
-
       Arg = ArgExpr.getAs<Expr>();
     }
 
@@ -12864,6 +12866,146 @@
   return new (Context) GNUNullExpr(Ty, TokenLoc);
 }
 
+namespace {
+/// A visitor for rebuilding SourceLocExpr's located in default initializers.
+struct RebuildSourceLocExprInInit : public TreeTransform<RebuildSourceLocExprInInit> {
+  typedef TreeTransform<RebuildSourceLocExprInInit> BaseTransform;
+
+  SourceLocation CallerLoc;
+  Decl *CallerDecl;
+
+public:
+  RebuildSourceLocExprInInit(Sema &S, SourceLocation CallerLoc, Decl *CallerDecl)
+      : BaseTransform(S), CallerLoc(CallerLoc), CallerDecl(CallerDecl) {}
+
+  bool AlwaysRebuild() { return true; }
+
+  StmtResult TransformStmt(Stmt *S) {
+    llvm_unreachable("unexpected statement!");
+  }
+
+  ExprResult TransformSourceLocExpr(SourceLocExpr *E) {
+    return SemaRef.BuildResolvedSourceLocExpr(E->getIdentType(),
+                                              E->getLocStart(), E->getLocEnd(),
+                                              CallerLoc, CallerDecl);
+  }
+};
+} // namespace
+
+
+/// Given a function expression of unknown-any type, try to rebuild it
+/// to have a function type.
+ExprResult
+Sema::TransformInitContainingSourceLocExpressions(Expr *Init,
+                                                  SourceLocation Loc) {
+  Decl *currentDecl = getDeclForCurContext();
+  ExprResult Result =
+      RebuildSourceLocExprInInit(*this, Loc, currentDecl).TransformExpr(Init);
+  return Result;
+}
+
+ExprResult Sema::ActOnSourceLocExpr(Scope *S, SourceLocExpr::IdentType Type,
+                                    SourceLocation BuiltinLoc,
+                                    SourceLocation RPLoc) {
+  bool RequiresTransform =
+      // The expression appears within a default argument
+      S->isFunctionPrototypeScope();
+
+  // Check if the expression appears within a NSDMI expression
+  if (S->isClassScope() && !ExprEvalContexts.empty()) {
+    if (auto *VD = dyn_cast_or_null<VarDecl>(
+            ExprEvalContexts.back().ManglingContextDecl))
+      RequiresTransform |= !VD->isStaticDataMember();
+  }
+
+  // SourceLocExpr's appearing in a default function argument or NSDMI can only
+  // be resolved once the location of the caller or constructor which requires
+  // them is known.
+  if (RequiresTransform)
+    return BuildSourceLocExpr(Type, BuiltinLoc, RPLoc);
+  return BuildResolvedSourceLocExpr(Type, BuiltinLoc, RPLoc, BuiltinLoc,
+                                    getDeclForCurContext());
+}
+
+static QualType buildSourceLocType(Sema &S, SourceLocExpr::IdentType Type,
+                                   bool MakeArray = false, int ArraySize = -1) {
+  assert(MakeArray == (ArraySize != -1));
+  bool IsIntType = Type == SourceLocExpr::Line || Type == SourceLocExpr::Column;
+  assert(!IsIntType || (IsIntType && !MakeArray));
+  if (IsIntType)
+    return S.Context.UnsignedIntTy;
+  QualType Ty = S.Context.CharTy;
+  // A C++ string literal has a const-qualified element type (C++ 2.13.4p1).
+  if (S.getLangOpts().CPlusPlus || S.getLangOpts().ConstStrings)
+    Ty = Ty.withConst();
+  if (!MakeArray)
+    return S.Context.getPointerType(Ty);
+  return S.Context.getConstantArrayType(Ty, llvm::APInt(32, ArraySize),
+                                        ArrayType::Normal, 0);
+}
+
+ExprResult Sema::BuildResolvedSourceLocExpr(SourceLocExpr::IdentType Type,
+                                            SourceLocation BuiltinLoc,
+                                            SourceLocation RPLoc,
+                                            SourceLocation CallerLoc,
+                                            Decl *CallerDecl) {
+  assert(CallerDecl);
+  PresumedLoc PLoc =
+      SourceMgr.getPresumedLoc(SourceMgr.getExpansionRange(CallerLoc).second);
+  assert(PLoc.isValid()); // FIXME: Learn how to handle this.
+
+  auto CreateString = [&](StringRef SVal) {
+    QualType StrTy = buildSourceLocType(*this, Type,
+                                        /*IsArray*/ true, SVal.size() + 1);
+    StringLiteral *Lit =
+        StringLiteral::Create(Context, SVal, StringLiteral::Ascii,
+                              /*Pascal*/ false, StrTy, CallerLoc);
+    assert(Lit && "should not be null");
+    return Lit;
+  };
+
+  ExprResult Res;
+  switch (Type) {
+  case SourceLocExpr::Column:
+  case SourceLocExpr::Line: {
+    unsigned Value =
+        Type == SourceLocExpr::Line ? PLoc.getLine() : PLoc.getColumn();
+    unsigned MaxWidth = Context.getTargetInfo().getIntWidth();
+    llvm::APInt IntVal(MaxWidth, Value);
+    Res = IntegerLiteral::Create(Context, IntVal, Context.UnsignedIntTy,
+                                 CallerLoc);
+    break;
+  }
+  case SourceLocExpr::File:
+    Res = CreateString(PLoc.getFilename());
+    break;
+  case SourceLocExpr::Function: {
+    if (CallerDecl == Context.getTranslationUnitDecl())
+      Res = CreateString("");
+    else
+      Res = CreateString(
+          PredefinedExpr::ComputeName(PredefinedExpr::Function, CallerDecl));
+    break;
+  }
+  }
+  if (Res.isInvalid())
+    return ExprError();
+  return BuildSourceLocExpr(Type, BuiltinLoc, RPLoc, Res.get());
+}
+
+ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentType Type,
+                                    SourceLocation BuiltinLoc,
+                                    SourceLocation RPLoc, Expr *SubExpr) {
+  // For __builtin_FILE and __builtin_FUNCTION the SubExpr will be a character
+  // array type. Decay this to the pointer type returned by the builtin.
+  if (SubExpr && SubExpr->getType()->isArrayType()) {
+    SubExpr = DefaultFunctionArrayLvalueConversion(SubExpr).get();
+    assert(SubExpr);
+  }
+  return new (Context) SourceLocExpr(Type, BuiltinLoc, RPLoc,
+                                     buildSourceLocType(*this, Type), SubExpr);
+}
+
 bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
                                               bool Diagnose) {
   if (!getLangOpts().ObjC1)
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1271,6 +1271,7 @@
   case Expr::PredefinedExprClass:
   case Expr::SizeOfPackExprClass:
   case Expr::StringLiteralClass:
+  case Expr::SourceLocExprClass:
     // These expressions can never throw.
     return CT_Cannot;
 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -62,7 +62,7 @@
 
   public:
     CheckDefaultArgumentVisitor(Expr *defarg, Sema *s)
-      : DefaultArg(defarg), S(s) {}
+        : DefaultArg(defarg), S(s) {}
 
     bool VisitExpr(Expr *Node);
     bool VisitDeclRefExpr(DeclRefExpr *DRE);
@@ -4542,17 +4542,37 @@
   return false;
 }
 
+
+static MemInitResult rebuildCtorInit(Sema &SemaRef, BaseAndFieldInfo &Info,
+                                     FieldDecl *Field, Expr *Init) {
+  // assert(!Field->getType()->isDependentType());
+  // assert(!Field->getInClassInitializer()->isTypeDependent());
+  SourceLocation Loc = Info.Ctor->getLocation();
+  ExprResult InitRes =
+      SemaRef.TransformInitContainingSourceLocExpressions(Init, Loc);
+  if (InitRes.isInvalid())
+    return true;
+  return SemaRef.BuildMemberInitializer(Field, InitRes.get(), Loc);
+}
+
 static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
                                     FieldDecl *Field, 
                                     IndirectFieldDecl *Indirect = nullptr) {
   if (Field->isInvalidDecl())
     return false;
 
   // Overwhelmingly common case: we have a direct initializer for this field.
   if (CXXCtorInitializer *Init =
-          Info.AllBaseFields.lookup(Field->getCanonicalDecl()))
+          Info.AllBaseFields.lookup(Field->getCanonicalDecl())) {
+    if (SourceLocExpr::containsSourceLocExpr(Init->getInit())) {
+      MemInitResult InitExpr =
+          rebuildCtorInit(SemaRef, Info, Field, Init->getInit());
+      if (InitExpr.isInvalid())
+        return true;
+      Init = InitExpr.get();
+    }
     return Info.addFieldInitializer(Init);
-
+  }
   // C++11 [class.base.init]p8:
   //   if the entity is a non-static data member that has a
   //   brace-or-equal-initializer and either
@@ -4569,20 +4589,31 @@
     return false;
 
   if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
-    ExprResult DIE =
-        SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field);
-    if (DIE.isInvalid())
+    if (SemaRef.CheckCXXDefaultInitExpr(Info.Ctor->getLocation(), Field))
       return true;
-    CXXCtorInitializer *Init;
-    if (Indirect)
-      Init = new (SemaRef.Context)
-          CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(),
-                             SourceLocation(), DIE.get(), SourceLocation());
-    else
-      Init = new (SemaRef.Context)
-          CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(),
-                             SourceLocation(), DIE.get(), SourceLocation());
-    return Info.addFieldInitializer(Init);
+    MemInitResult Init(/*Invalid*/ true);
+
+    if (SourceLocExpr::containsSourceLocExpr(Field->getInClassInitializer()))
+      Init =
+          rebuildCtorInit(SemaRef, Info, Field, Field->getInClassInitializer());
+    else {
+      ExprResult DIE =
+          SemaRef.BuildCXXDefaultInitExpr(Info.Ctor->getLocation(), Field);
+      if (DIE.isInvalid())
+        return true;
+      if (Indirect)
+        Init = new (SemaRef.Context)
+            CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(),
+                               SourceLocation(), DIE.get(), SourceLocation());
+      else
+        Init = new (SemaRef.Context)
+            CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(),
+                               SourceLocation(), DIE.get(), SourceLocation());
+      assert(!Init.isInvalid());
+    }
+    if (Init.isInvalid())
+      return true;
+    return Info.addFieldInitializer(Init.get());
   }
 
   // Don't initialize incomplete or zero-length arrays.
@@ -12397,16 +12428,15 @@
       ParenRange);
 }
 
-ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
+bool Sema::CheckCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
   assert(Field->hasInClassInitializer());
-
   // If we already have the in-class initializer nothing needs to be done.
   if (Field->getInClassInitializer())
-    return CXXDefaultInitExpr::Create(Context, Loc, Field);
+    return false;
 
   // If we might have already tried and failed to instantiate, don't try again.
   if (Field->isInvalidDecl())
-    return ExprError();
+    return true;
 
   // Maybe we haven't instantiated the in-class initializer. Go check the
   // pattern FieldDecl to see if it has one.
@@ -12440,11 +12470,10 @@
                                       getTemplateInstantiationArgs(Field))) {
       // Don't diagnose this again.
       Field->setInvalidDecl();
-      return ExprError();
+      return true;
     }
-    return CXXDefaultInitExpr::Create(Context, Loc, Field);
+    return false;
   }
-
   // DR1351:
   //   If the brace-or-equal-initializer of a non-static data member
   //   invokes a defaulted default constructor of its class or of an
@@ -12466,7 +12495,13 @@
   // Recover by marking the field invalid, unless we're in a SFINAE context.
   if (!isSFINAEContext())
     Field->setInvalidDecl();
-  return ExprError();
+  return true;
+}
+
+ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
+  if (CheckCXXDefaultInitExpr(Loc, Field))
+    return ExprError();
+  return CXXDefaultInitExpr::Create(Context, Loc, Field);
 }
 
 void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -1107,6 +1107,22 @@
   return nullptr;
 }
 
+Decl *Sema::getDeclForCurContext() {
+  Decl *currentDecl = nullptr;
+  if (const BlockScopeInfo *BSI = getCurBlock())
+    currentDecl = BSI->TheDecl;
+  else if (const LambdaScopeInfo *LSI = getCurLambda())
+    currentDecl = LSI->CallOperator;
+  else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion())
+    currentDecl = CSI->TheCapturedDecl;
+  else
+    currentDecl = getCurFunctionOrMethodDecl();
+
+  if (!currentDecl)
+    currentDecl = Context.getTranslationUnitDecl();
+  return currentDecl;
+}
+
 void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
   // FIXME: It doesn't make sense to me that DiagID is an incoming argument here
   // and yet we also use the current diag ID on the DiagnosticsEngine. This has
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -619,6 +619,10 @@
 /// [GNU]   '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
 /// [GNU]   '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
 ///                                     assign-expr ')'
+/// [GNU]   '__builtin_FILE' '(' ')'
+/// [GNU]   '__builtin_FUNCTION' '(' ')'
+/// [GNU]   '__builtin_LINE' '(' ')'
+/// [CLANG] '__builtin_COLUMN' '(' ')'
 /// [GNU]   '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
 /// [GNU]   '__null'
 /// [OBJC]  '[' objc-message-expr ']'
@@ -1072,6 +1076,10 @@
   case tok::kw___builtin_choose_expr:
   case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
   case tok::kw___builtin_convertvector:
+  case tok::kw___builtin_COLUMN:
+  case tok::kw___builtin_FILE:
+  case tok::kw___builtin_FUNCTION:
+  case tok::kw___builtin_LINE:
     return ParseBuiltinPrimaryExpression();
   case tok::kw___null:
     return Actions.ActOnGNUNullExpr(ConsumeToken());
@@ -1991,6 +1999,10 @@
 /// [GNU]   '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
 ///                                     assign-expr ')'
 /// [GNU]   '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [GNU]   '__builtin_FILE' '(' ')'
+/// [GNU]   '__builtin_FUNCTION' '(' ')'
+/// [GNU]   '__builtin_LINE' '(' ')'
+/// [CLANG] '__builtin_COLUMN' '(' ')'
 /// [OCL]   '__builtin_astype' '(' assignment-expression ',' type-name ')'
 ///
 /// [GNU] offsetof-member-designator:
@@ -2210,6 +2222,34 @@
                                          ConsumeParen());
     break;
   }
+  case tok::kw___builtin_COLUMN:
+  case tok::kw___builtin_FILE:
+  case tok::kw___builtin_FUNCTION:
+  case tok::kw___builtin_LINE: {
+    // Attempt to consume the r-paren.
+    if (Tok.isNot(tok::r_paren)) {
+      Diag(Tok, diag::err_expected) << tok::r_paren;
+      SkipUntil(tok::r_paren, StopAtSemi);
+      return ExprError();
+    }
+    SourceLocExpr::IdentType Type = [&] {
+      switch (T) {
+      case tok::kw___builtin_FILE:
+        return SourceLocExpr::File;
+      case tok::kw___builtin_FUNCTION:
+        return SourceLocExpr::Function;
+      case tok::kw___builtin_LINE:
+        return SourceLocExpr::Line;
+      case tok::kw___builtin_COLUMN:
+        return SourceLocExpr::Column;
+      default:
+        llvm_unreachable("invalid keyword");
+      }
+    }();
+    Res = Actions.ActOnSourceLocExpr(getCurScope(), Type, StartLoc,
+                                     ConsumeParen());
+    break;
+  }
   }
 
   if (Res.isInvalid())
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -572,7 +572,9 @@
   Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) {
     return EmitLoadOfLValue(E);
   }
-
+  Value *VisitSourceLocExpr(SourceLocExpr *SLE) {
+    return Visit(SLE->getSubExpr());
+  }
   Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
     return Visit(DAE->getExpr());
   }
@@ -1778,7 +1780,7 @@
   }
 
   case CK_IntToOCLSampler:
-    return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+    return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
 
   } // end of switch
 
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -810,6 +810,10 @@
     llvm_unreachable("Invalid CastKind");
   }
 
+  llvm::Constant *VisitSourceLocExpr(SourceLocExpr *SLE, QualType T) {
+    return Visit(SLE->getSubExpr(), T);
+  }
+
   llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE, QualType T) {
     return Visit(DAE->getExpr(), T);
   }
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -182,6 +182,7 @@
     CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
     Visit(DIE->getExpr());
   }
+  void VisitSourceLocExpr(SourceLocExpr *SLE) { Visit(SLE->getSubExpr()); }
   void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
   void VisitCXXConstructExpr(const CXXConstructExpr *E);
   void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1810,6 +1810,12 @@
   VisitExpr(E);
 }
 
+void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) {
+  VisitExpr(E);
+  if (E->getSubExpr())
+    VisitExpr(E->getSubExpr());
+}
+
 void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
   VisitExpr(S);
 }
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1308,6 +1308,10 @@
 //  Expr printing methods.
 //===----------------------------------------------------------------------===//
 
+void StmtPrinter::VisitSourceLocExpr(SourceLocExpr *Node) {
+  OS << Node->getBuiltinStr() << "()";
+}
+
 void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
   if (auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) {
     OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy);
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3373,7 +3373,7 @@
   case Expr::AsTypeExprClass:
   case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
-  {
+  case Expr::SourceLocExprClass: {
     if (!NullOut) {
       // As bad as this diagnostic is, it's better than crashing.
       DiagnosticsEngine &Diags = Context.getDiags();
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -4510,6 +4510,11 @@
       return Error(E);
     return StmtVisitorTy::Visit(E->getExpr());
   }
+  bool VisitSourceLocExpr(const SourceLocExpr *E) {
+    if (auto *SubE = E->getSubExpr())
+      return StmtVisitorTy::Visit(E->getSubExpr());
+    return Error(E);
+  }
   // We cannot create any objects for which cleanups are required, so there is
   // nothing to do here; all cleanups must come from unevaluated subexpressions.
   bool VisitExprWithCleanups(const ExprWithCleanups *E)
@@ -10281,6 +10286,9 @@
     // GCC considers the GNU __null value to be an integral constant expression.
     return NoDiag();
 
+  case Expr::SourceLocExprClass:
+    return CheckEvalInICE(cast<SourceLocExpr>(E)->getSubExpr(), Ctx);
+
   case Expr::SubstNonTypeTemplateParmExprClass:
     return
       CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -190,6 +190,7 @@
   case Expr::ArrayInitIndexExprClass:
   case Expr::NoInitExprClass:
   case Expr::DesignatedInitUpdateExprClass:
+  case Expr::SourceLocExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1829,6 +1829,47 @@
   return OverOps[Opc];
 }
 
+SourceLocExpr::SourceLocExpr(IdentType Type, SourceLocation BLoc,
+                             SourceLocation RParenLoc, QualType Ty, Expr *E)
+    : Expr(SourceLocExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false,
+           false),
+      BuiltinLoc(BLoc), RParenLoc(RParenLoc), Value(E) {
+  SourceLocExprBits.Type = Type;
+  assert(!Ty->isDependentType() && "Type should never be dependent");
+  assert(!Ty->isArrayType() && "Type should never be an array");
+}
+
+const char *SourceLocExpr::getBuiltinStr() const {
+  switch (getIdentType()) {
+  case File:
+    return "__builtin_FILE";
+  case Function:
+    return "__builtin_FUNCTION";
+  case Line:
+    return "__builtin_LINE";
+  case Column:
+    return "__builtin_COLUMN";
+  }
+}
+
+namespace {
+class CheckForSourceLocVisitor
+    : public ConstStmtVisitor<CheckForSourceLocVisitor, bool> {
+
+public:
+  CheckForSourceLocVisitor() {}
+  bool VisitExpr(const Expr *Node) {
+    return llvm::any_of(Node->children(),
+                        [&](const Stmt *SubStmt) { return Visit(SubStmt); });
+  }
+  bool VisitSourceLocExpr(const SourceLocExpr *SLE) { return true; }
+};
+} // namespace
+
+bool SourceLocExpr::containsSourceLocExpr(const Expr *E) {
+  return CheckForSourceLocVisitor{}.Visit(E);
+}
+
 InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
                            ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
   : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
@@ -2954,6 +2995,7 @@
   case ObjCAvailabilityCheckExprClass:
   case CXXUuidofExprClass:
   case OpaqueValueExprClass:
+  case SourceLocExprClass:
     // These never have a side-effect.
     return false;
 
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1341,6 +1341,8 @@
       EXPR_CHOOSE,
       /// \brief A GNUNullExpr record.
       EXPR_GNU_NULL,
+      /// \brief A SourceLocExpr record
+      EXPR_SOURCE_LOC,
       /// \brief A ShuffleVectorExpr record.
       EXPR_SHUFFLE_VECTOR,
       /// \brief A ConvertVectorExpr record.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2336,6 +2336,10 @@
   /// in a 'block', this returns the containing context.
   NamedDecl *getCurFunctionOrMethodDecl();
 
+  /// getDeclForCurContext - Return the Decl for the current block, lambda,
+  /// captured statement, function, or translation unit.
+  Decl *getDeclForCurContext();
+
   /// Add this decl to the scope shadowed decl chains.
   void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
 
@@ -4395,6 +4399,38 @@
   ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E,
                             TypeSourceInfo *TInfo, SourceLocation RPLoc);
 
+  // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(),
+  // __builtin_COLUMN()
+  ExprResult ActOnSourceLocExpr(Scope *S, SourceLocExpr::IdentType Type,
+                                SourceLocation BuiltinLoc,
+                                SourceLocation RPLoc);
+
+  /// \brief build a potentially resolved SourceLocExpr.
+  ///
+  /// \param SubExpr - null when the SourceLocExpr is unresolved, otherwise
+  /// SubExpr will be a literal expression representing the value of the
+  /// builtin call.
+  ExprResult BuildSourceLocExpr(SourceLocExpr::IdentType Type,
+                                SourceLocation BuiltinLoc, SourceLocation RPLoc,
+                                Expr *SubExpr = nullptr);
+
+  /// \brief Build a SourceLocExpr with a value representing source information
+  /// at the SourceLocation specified by 'AtLoc' and in the context specified
+  /// by 'CurContext'.
+  ///
+  /// \param AtLoc The location at which the builtin should be evaluated.
+  ///
+  /// \param CurContext The context in which the builtin should be evaluated.
+  ExprResult BuildResolvedSourceLocExpr(SourceLocExpr::IdentType Type,
+                                        SourceLocation BuiltinLoc,
+                                        SourceLocation RPLoc,
+                                        SourceLocation AtLoc, Decl *CurContext);
+
+  /// \brief Transform an expression containing unresolved SourceLocExpr's while
+  /// resolving them to the specified `Loc`
+  ExprResult TransformInitContainingSourceLocExpressions(Expr *E,
+                                                         SourceLocation Loc);
+
   // __null
   ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc);
 
@@ -4613,6 +4649,12 @@
                         bool IsStdInitListInitialization, bool RequiresZeroInit,
                         unsigned ConstructKind, SourceRange ParenRange);
 
+  /// Instantiate or parse a C++ default init expression as necessary.
+  /// Return true on error.
+  bool CheckCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field);
+
+  /// BuildCXXDefaultInitExpr - Creates a CXXDefaultInitExpr, instantiating
+  /// the default expr if needed.
   ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field);
 
 
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -388,6 +388,11 @@
 KEYWORD(__attribute                 , KEYALL)
 KEYWORD(__builtin_choose_expr       , KEYALL)
 KEYWORD(__builtin_offsetof          , KEYALL)
+KEYWORD(__builtin_FILE              , KEYALL)
+KEYWORD(__builtin_FUNCTION          , KEYALL)
+KEYWORD(__builtin_LINE              , KEYALL)
+KEYWORD(__builtin_COLUMN            , KEYALL)
+
 // __builtin_types_compatible_p is a GNU C extension that we handle like a C++
 // type trait.
 TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX)
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -91,6 +91,7 @@
 def VAArgExpr : DStmt<Expr>;
 def GenericSelectionExpr : DStmt<Expr>;
 def PseudoObjectExpr : DStmt<Expr>;
+def SourceLocExpr : DStmt<Expr>;
 
 // Atomic expressions
 def AtomicExpr : DStmt<Expr>;
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -261,6 +261,16 @@
     unsigned IsImplicit : 1;
   };
 
+  class SourceLocExprBitfields {
+    friend class SourceLocExpr;
+
+    unsigned : NumExprBits;
+
+    /// \brief The type of source location builtin represented by the
+    /// SourceLocExpr. Ex. __builtin_LINE, __builtin_FUNCTION, ect.
+    unsigned Type : 2;
+  };
+
   union {
     StmtBitfields StmtBits;
     CompoundStmtBitfields CompoundStmtBits;
@@ -278,6 +288,7 @@
     InitListExprBitfields InitListExprBits;
     TypeTraitExprBitfields TypeTraitExprBits;
     CoawaitExprBitfields CoawaitBits;
+    SourceLocExprBitfields SourceLocExprBits;
   };
 
   friend class ASTStmtReader;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2485,6 +2485,8 @@
 DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
 DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
 DEF_TRAVERSE_STMT(StmtExpr, {})
+DEF_TRAVERSE_STMT(SourceLocExpr, {})
+
 DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
   TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
   if (S->hasExplicitTemplateArgs()) {
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -3811,6 +3811,71 @@
   }
 };
 
+/// BuiltinSourceLocExpr - Represents a function call to one of
+/// __builtin_LINE(), __builtin_COLUMN(), __builtin_FUNCTION(), or
+/// __BUILTIN_FILE()
+class SourceLocExpr final : public Expr {
+public:
+  enum IdentType { Function, File, Line, Column };
+
+private:
+  SourceLocation BuiltinLoc, RParenLoc;
+  Stmt *Value;
+
+public:
+  SourceLocExpr(IdentType Type, SourceLocation BLoc, SourceLocation RParenLoc,
+                QualType Ty, Expr *E = nullptr);
+
+  /// \brief Build an empty call expression.
+  explicit SourceLocExpr(EmptyShell Empty)
+      : Expr(SourceLocExprClass, Empty), Value(nullptr) {}
+
+  /// \brief Check if an expression contains a SourceLocExpr as a subexpression.
+  static bool containsSourceLocExpr(const Expr *E);
+
+  /// \brief Return a string representing the name of the specific builtin
+  /// function.
+  const char *getBuiltinStr() const LLVM_READONLY;
+
+  IdentType getIdentType() const LLVM_READONLY {
+    return static_cast<IdentType>(SourceLocExprBits.Type);
+  }
+
+  /// \brief If the SourceLocExpr has been resolved return the subexpression
+  /// representing the resolved value. Otherwise return null.
+  const Expr *getSubExpr() const { return cast_or_null<Expr>(Value); }
+  Expr *getSubExpr() { return cast_or_null<Expr>(Value); }
+
+  /// \brief True iff the value for the SourceLocExpr has been determined.
+  bool isUnresolved() const { return Value == nullptr; }
+
+  SourceLocation getLocation() const LLVM_READONLY { return BuiltinLoc; }
+  SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+  SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
+  child_range children() {
+    return Value ? child_range(&Value, &Value + 1)
+                 : child_range(child_iterator(), child_iterator());
+  }
+
+  const_child_range children() const {
+    return Value ? const_child_range(&Value, &Value + 1)
+                 : const_child_range(child_iterator(), child_iterator());
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SourceLocExprClass;
+  }
+
+private:
+  friend class ASTStmtReader;
+
+  void setIdentType(IdentType T) { SourceLocExprBits.Type = T; }
+  void setSubExpr(Expr *E) { Value = E; }
+  void setLocStart(SourceLocation L) { BuiltinLoc = L; }
+  void setLocEnd(SourceLocation L) { RParenLoc = L; }
+};
+
 /// @brief Describes an C or C++ initializer list.
 ///
 /// InitListExpr describes an initializer list, which can be used to
Index: docs/LanguageExtensions.rst
===================================================================
--- docs/LanguageExtensions.rst
+++ docs/LanguageExtensions.rst
@@ -2067,6 +2067,61 @@
 token `none`. If a user calls `__builin_suspend`, clang will insert `token none`
 as the first argument to the intrinsic.
 
+Source location builtins
+------------------------
+
+Clang provides experimental builtins to support C++ standard library implementation
+of `std::experimental::source_location` as specified in  http://wg21.link/N4600.
+With the exception of `__builtin_COLUMN`, these builtins are also implemented by
+GCC.
+
+**Syntax**:
+
+.. code-block:: c
+
+  const char *__builtin_FILE();
+  const char *__builtin_FUNCTION();
+  unsigned    __builtin_LINE();
+  unsigned    __builtin_COLUMN(); // Clang only
+
+**Example of use**:
+
+.. code-block:: c++
+
+  void my_assert(bool pred, int line = __builtin_LINE(), // Captures line of caller
+                 const char* file = __builtin_FILE(),
+                 const char* function = __builtin_FUNCTION()) {
+    if (pred) return;
+    printf("%s:%d assertion failed in function %s\n", file, line, function);
+    std::abort();
+  }
+
+  struct MyAggregateType {
+    int x;
+    int line = __builtin_LINE(); // captures line where aggregate initialization occurs
+  };
+  static_assert(MyAggregateType{42}.line == __LINE__);
+
+  struct MyClassType {
+    int line = __builtin_LINE(); // captures line of the constructor used during initialization
+    constexpr MyClassType(int) { assert(line == __LINE__); }
+  };
+
+**Description**:
+
+The builtins `__builtin_LINE`, `__builtin_FUNCTION`, and `__builtin_FILE` return
+the values, at the "invocation point", for `__LINE__`, `__FUNCTION__`, and
+`__FILE__` respectively. These builtins are constant expressions.
+
+When the builtins appears as part of a default function argument the invocation
+point is the location of the caller. When the builtins appear as part of a
+NSDMI the invocation point is the location of the constructor or
+aggregate initialization used to create the object. Otherwise the invocation
+point is the same as the location of the builtin.
+
+When the invocation point of `__builtin_FUNCTION` is not a function scope the
+empty string is returned.
+
 Non-standard C++11 Attributes
 =============================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to