diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 0b43ae4ece3..6ff994fd599 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1492,7 +1492,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
       temp_override<tree> ovr (current_function_decl);
       if (ctx->call && ctx->call->fundef)
 	current_function_decl = ctx->call->fundef->decl;
-      return fold_builtin_source_location (EXPR_LOCATION (t));
+      return fold_builtin_source_location (t);
     }
 
   int strops = 0;
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 983f2a566a6..6ad8458ab28 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -722,7 +722,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 		break;
 	      case CP_BUILT_IN_SOURCE_LOCATION:
 		*expr_p
-		  = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
+		  = fold_builtin_source_location (*expr_p);
 		break;
 	      case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
 		*expr_p
@@ -2850,7 +2850,7 @@ cp_fold (tree x)
 	      case CP_BUILT_IN_IS_CONSTANT_EVALUATED:
 		break;
 	      case CP_BUILT_IN_SOURCE_LOCATION:
-		x = fold_builtin_source_location (EXPR_LOCATION (x));
+		x = fold_builtin_source_location (x);
 		break;
 	      case CP_BUILT_IN_IS_CORRESPONDING_MEMBER:
 	        x = fold_builtin_is_corresponding_member
@@ -2872,7 +2872,7 @@ cp_fold (tree x)
 	    && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
 				  BUILT_IN_FRONTEND))
 	  {
-	    x = fold_builtin_source_location (EXPR_LOCATION (x));
+	    x = fold_builtin_source_location (x);
 	    break;
 	  }
 
@@ -3171,12 +3171,11 @@ process_stmt_assume_attribute (tree std_attrs, tree statement,
   return remove_attribute ("gnu", "assume", std_attrs);
 }
 
-/* Helper of fold_builtin_source_location, return the
-   std::source_location::__impl type after performing verification
-   on it.  LOC is used for reporting any errors.  */
+/* Return the type std::source_location::__impl after performing verification
+   on it.  */
 
-static tree
-get_source_location_impl_type (location_t loc)
+tree
+get_source_location_impl_type ()
 {
   tree name = get_identifier ("source_location");
   tree decl = lookup_qualified_name (std_node, name);
@@ -3184,9 +3183,9 @@ get_source_location_impl_type (location_t loc)
     {
       auto_diagnostic_group d;
       if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
-	qualified_name_lookup_error (std_node, name, decl, loc);
+	qualified_name_lookup_error (std_node, name, decl, input_location);
       else
-	error_at (loc, "%qD is not a type", decl);
+	error ("%qD is not a type", decl);
       return error_mark_node;
     }
   name = get_identifier ("__impl");
@@ -3196,15 +3195,15 @@ get_source_location_impl_type (location_t loc)
     {
       auto_diagnostic_group d;
       if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
-	qualified_name_lookup_error (type, name, decl, loc);
+	qualified_name_lookup_error (type, name, decl, input_location);
       else
-	error_at (loc, "%qD is not a type", decl);
+	error ("%qD is not a type", decl);
       return error_mark_node;
     }
   type = TREE_TYPE (decl);
   if (TREE_CODE (type) != RECORD_TYPE)
     {
-      error_at (loc, "%qD is not a class type", decl);
+      error ("%qD is not a class type", decl);
       return error_mark_node;
     }
 
@@ -3221,8 +3220,7 @@ get_source_location_impl_type (location_t loc)
 	    {
 	      if (TREE_TYPE (field) != const_string_type_node)
 		{
-		  error_at (loc, "%qD does not have %<const char *%> type",
-			    field);
+		  error ("%qD does not have %<const char *%> type", field);
 		  return error_mark_node;
 		}
 	      cnt++;
@@ -3232,7 +3230,7 @@ get_source_location_impl_type (location_t loc)
 	    {
 	      if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
 		{
-		  error_at (loc, "%qD does not have integral type", field);
+		  error ("%qD does not have integral type", field);
 		  return error_mark_node;
 		}
 	      cnt++;
@@ -3244,9 +3242,9 @@ get_source_location_impl_type (location_t loc)
     }
   if (cnt != 4)
     {
-      error_at (loc, "%<std::source_location::__impl%> does not contain only "
-		     "non-static data members %<_M_file_name%>, "
-		     "%<_M_function_name%>, %<_M_line%> and %<_M_column%>");
+      error ("%<std::source_location::__impl%> does not contain only "
+	     "non-static data members %<_M_file_name%>, "
+	     "%<_M_function_name%>, %<_M_line%> and %<_M_column%>");
       return error_mark_node;
     }
   return build_qualified_type (type, TYPE_QUAL_CONST);
@@ -3337,21 +3335,21 @@ static GTY(()) hash_table <source_location_table_entry_hash>
   *source_location_table;
 static GTY(()) unsigned int source_location_id;
 
-/* Fold __builtin_source_location () call.  LOC is the location
-   of the call.  */
+/* Fold the __builtin_source_location () call T.  */
 
 tree
-fold_builtin_source_location (location_t loc)
+fold_builtin_source_location (const_tree t)
 {
-  if (source_location_impl == NULL_TREE)
-    {
-      auto_diagnostic_group d;
-      source_location_impl = get_source_location_impl_type (loc);
-      if (source_location_impl == error_mark_node)
-	inform (loc, "evaluating %qs", "__builtin_source_location");
-    }
+  gcc_assert (TREE_CODE (t) == CALL_EXPR);
+  /* TREE_TYPE (t) is const std::source_location::__impl*  */
+  tree source_location_impl = TREE_TYPE (TREE_TYPE (t));
   if (source_location_impl == error_mark_node)
     return build_zero_cst (const_ptr_type_node);
+  gcc_assert (CLASS_TYPE_P (source_location_impl)
+	      && id_equal (DECL_NAME (TYPE_NAME (source_location_impl)),
+			   "__impl"));
+
+  location_t loc = EXPR_LOCATION (t);
   if (source_location_table == NULL)
     source_location_table
       = hash_table <source_location_table_entry_hash>::create_ggc (64);
@@ -3427,7 +3425,7 @@ fold_builtin_source_location (location_t loc)
       entryp->var = var;
     }
 
-  return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
+  return build_fold_addr_expr_with_type_loc (loc, var, TREE_TYPE (t));
 }
 
 #include "gt-cp-cp-gimplify.h"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index addd26ea077..8600e6067f9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -235,8 +235,6 @@ enum cp_tree_index
 
     CPTI_PSEUDO_CONTRACT_VIOLATION,
 
-    CPTI_SOURCE_LOCATION_IMPL,
-
     CPTI_FALLBACK_DFLOAT32_TYPE,
     CPTI_FALLBACK_DFLOAT64_TYPE,
     CPTI_FALLBACK_DFLOAT128_TYPE,
@@ -395,9 +393,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 /* A node which matches any template argument.  */
 #define any_targ_node			cp_global_trees[CPTI_ANY_TARG]
 
-/* std::source_location::__impl class.  */
-#define source_location_impl		cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
-
 /* Node to indicate default access. This must be distinct from the
    access nodes in tree.h.  */
 
@@ -8295,7 +8290,8 @@ extern tree process_stmt_hotness_attribute	(tree, location_t);
 extern tree build_assume_call			(location_t, tree);
 extern tree process_stmt_assume_attribute	(tree, tree, location_t);
 extern bool simple_empty_class_p		(tree, tree, tree_code);
-extern tree fold_builtin_source_location	(location_t);
+extern tree fold_builtin_source_location	(const_tree);
+extern tree get_source_location_impl_type	();
 
 /* in name-lookup.cc */
 extern tree strip_using_decl                    (tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 715c739b6e5..07c55ba19b6 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -4669,9 +4669,13 @@ cxx_init_decl_processing (void)
 			    BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
-  tree cptr_ftype = build_function_type_list (const_ptr_type_node, NULL_TREE);
+  /* The concrete return type of __builtin_source_location is
+     const std::source_location::__impl*, but we can't form the type
+     at this point.  So we initially use a deduced return type and
+     update it from require_deduced_type upon first use.  */
+  tree auto_ftype = build_function_type_list (make_auto (), NULL_TREE);
   decl = add_builtin_function ("__builtin_source_location",
-			       cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION,
+			       auto_ftype, CP_BUILT_IN_SOURCE_LOCATION,
 			       BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
@@ -18751,6 +18755,23 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
 {
   if (undeduced_auto_decl (decl))
     {
+      if (TREE_CODE (decl) == FUNCTION_DECL
+	  && fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
+	  && DECL_FE_FUNCTION_CODE (decl) == CP_BUILT_IN_SOURCE_LOCATION)
+	{
+	  /* Determine the return type of __builtin_source_location.  */
+	  tree type = get_source_location_impl_type ();
+	  if (type == error_mark_node)
+	    {
+	      inform (input_location, "using %qs", "__builtin_source_location");
+	      return false;
+	    }
+	  type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+	  type = build_pointer_type (type);
+	  apply_deduced_return_type (decl, type);
+	  return true;
+	}
+
       if (warning_suppressed_p (decl) && seen_error ())
 	/* We probably already complained about deduction failure.  */;
       else if (complain & tf_error)
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc10.C b/gcc/testsuite/g++.dg/cpp2a/srcloc10.C
index 1be78d9f7bd..aa8cf98880c 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc10.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc10.C
@@ -10,4 +10,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc11.C b/gcc/testsuite/g++.dg/cpp2a/srcloc11.C
index abc850fcd43..07281ca0ad0 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc11.C
@@ -10,4 +10,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc12.C b/gcc/testsuite/g++.dg/cpp2a/srcloc12.C
index 49a7e569b7f..445c4a13374 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc12.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc12.C
@@ -11,4 +11,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::_M_file_name' does not have 'const char \\*' type" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc13.C b/gcc/testsuite/g++.dg/cpp2a/srcloc13.C
index ee7b1248354..d63f6c7d932 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc13.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc13.C
@@ -12,4 +12,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::_M_line' does not have integral type" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc3.C b/gcc/testsuite/g++.dg/cpp2a/srcloc3.C
index 29587e4ebb5..324e03cd548 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc3.C
@@ -2,4 +2,4 @@
 
 auto x = __builtin_source_location ();	// { dg-error "'source_location' is not a member of 'std'" }
 // { dg-message "std::source_location' is defined in header '<source_location>'; did you forget to '#include <source_location>'" "" { target *-*-* } .-1 }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-2 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc4.C b/gcc/testsuite/g++.dg/cpp2a/srcloc4.C
index c10f64b95d2..9e92c449fc3 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc4.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc4.C
@@ -5,4 +5,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'void std::source_location\\(\\)' is not a type" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc5.C b/gcc/testsuite/g++.dg/cpp2a/srcloc5.C
index ce7170b6dce..ed4b9351f74 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc5.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc5.C
@@ -6,4 +6,4 @@ namespace std {
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location'\[^\n\r]*is not a class type" }
 // { dg-error "'__impl' is not a member of 'std::source_location'" "" { target *-*-* } .-1 }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-2 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc6.C b/gcc/testsuite/g++.dg/cpp2a/srcloc6.C
index 89c6887cb46..bec51e290b2 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc6.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc6.C
@@ -6,4 +6,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'__impl' is not a member of 'std::source_location'" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc7.C b/gcc/testsuite/g++.dg/cpp2a/srcloc7.C
index ef56edf9426..c81fa63f418 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc7.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc7.C
@@ -7,4 +7,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl\\(\\)' is not a type" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc8.C b/gcc/testsuite/g++.dg/cpp2a/srcloc8.C
index caef812b464..158cc3f93d1 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc8.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc8.C
@@ -7,4 +7,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl()' is not a class type" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc9.C b/gcc/testsuite/g++.dg/cpp2a/srcloc9.C
index 47fce003913..618e0935632 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc9.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc9.C
@@ -8,4 +8,4 @@ namespace std {
 }
 
 auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
-// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
+// { dg-message "using '__builtin_source_location'" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/modules/pr100881_a.C b/gcc/testsuite/g++.dg/modules/pr100881_a.C
new file mode 100644
index 00000000000..94e9f742798
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr100881_a.C
@@ -0,0 +1,28 @@
+// PR c++/100881
+// { dg-additional-options "-std=c++20 -fmodules-ts" }
+// { dg-module-cmi pr100881 }
+module;
+#include <source_location>
+export module pr100881;
+
+export consteval int
+current_line_fn(const std::source_location& loc = std::source_location::current())
+{
+  return loc.line();
+}
+
+export struct current_line_cls
+{
+  int line = std::source_location::current().line();
+};
+
+export template<class T> consteval int
+current_line_fn_tmpl(const std::source_location& loc = std::source_location::current())
+{
+  return loc.line();
+}
+
+export template<class T> struct current_line_cls_tmpl
+{
+  int line = std::source_location::current().line();
+};
diff --git a/gcc/testsuite/g++.dg/modules/pr100881_b.C b/gcc/testsuite/g++.dg/modules/pr100881_b.C
new file mode 100644
index 00000000000..7f25b21b354
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr100881_b.C
@@ -0,0 +1,8 @@
+// PR c++/100881
+// { dg-additional-options "-std=c++20 -fmodules-ts" }
+import pr100881;
+
+static_assert(current_line_fn() == 5);
+static_assert(current_line_cls{}.line == 6);
+static_assert(current_line_fn_tmpl<int>() == 7);
+static_assert(current_line_cls_tmpl<int>{}.line == 8);
