     key_or_path = expand_key_or_path(key_or_path, __CALLER__)
 
     quote do
-      Application.__compile_env__!(unquote(app), unquote(key_or_path), __ENV__)
-    end
-  end
-
-  @doc false
-  def __compile_env__!(app, key_or_path, env) do
+      Application.compile_env!(__ENV__, unquote(app), unquote(key_or_path))
+    end
+  end
+
+  @doc """
+  Reads the application environment at compilation time from a macro
+  or raises.
+
+  Typically, developers will use `compile_env!/2`. This function must
+  only be invoked from macros who wish to read the compilation environment
+  dynamically.
+
+  It expects a `Macro.Env` as first argument, where the `Macro.Env` is
+  typically the `__CALLER__` in a macro. It raises if `Macro.Env` comes
+  from a function.
+  """
+  @doc since: "1.14.0"
+  @spec compile_env!(Macro.Env.t(), app, key | list) :: value
+  def compile_env!(%Macro.Env{} = env, app, key_or_path) do
+    if env.function do
+      raise "Application.compile_env!/3 cannot be called inside functions, only in the module body"
+    end
+
     case fetch_compile_env(app, key_or_path, env) do
       {:ok, value} ->
         value

    key_or_path = expand_key_or_path(key_or_path, __CALLER__)

    quote do
      Application.__compile_env__(unquote(app), unquote(key_or_path), unquote(default), __ENV__)
    end
  end


  defp expand_key_or_path(other, _env),
    do: other

  @doc """
  Reads the application environment at compilation time from a macro.

  Typically, developers will use `compile_env/3`. This function must
  only be invoked from macros who wish to read the compilation environment
  dynamically.

  It expects a `Macro.Env` as first argument, where the `Macro.Env` is
  typically the `__CALLER__` in a macro. It raises if `Macro.Env` comes
  from a function.
  """
  @doc since: "1.14.0"
  @spec compile_env(Macro.Env.t(), app, key | list, value) :: value
  def compile_env(%Macro.Env{} = env, app, key_or_path, default) do
    if env.function do
      raise "Application.compile_env/4 cannot be called inside functions, only in the module body"
    end

    case fetch_compile_env(app, key_or_path, env) do
      {:ok, value} -> value
      :error -> default
