Commit 24614ce814 for perl
commit 24614ce81434efe3befc8402ff43f356a1fab6dd
Author: Karl Williamson <khw@cpan.org>
Date: Wed Oct 21 20:54:19 2026 -0600
perlintern: Add symbol visibilities
The visibility of some symbols listed in perlintern is restricted. This
commit notes the visibility of all symbols in the pod.
diff --git a/autodoc.pl b/autodoc.pl
index f5292277c6..1d8ed90e3a 100644
--- a/autodoc.pl
+++ b/autodoc.pl
@@ -87,6 +87,13 @@ my $item_flags_re = qr/[B dD fF mM nN oO pT uU Wx;]/xx;
# Only certain flags are acceptable for apidoc_flag
my $flag_flags_re = qr/[ A C dD eE h m n p Q u X ] /xx;
+my %visibility_name = (
+ C => "Everywhere",
+ E => "Core and extensions only",
+ Q => "Core and ext/re only",
+ e => "Core only",
+ );
+
# Certain functions have plain and no_context versions, and meet the criteria
# stated here. Each of their pods has been modified to have a marker line
# which this program replaces by this wording. This way we can tweak the
@@ -1878,6 +1885,8 @@ sub docout ($fh, $section_name, $element_name, $docref) {
my @experimental;
my @back_compat;
my @xrefs;
+ my %visibility;
+ $visibility{longest_name} = 0;
for (my $i = 0; $i < @items; $i++) {
last if $docref->{'xref_only'}; # Place holder
@@ -1895,6 +1904,27 @@ sub docout ($fh, $section_name, $element_name, $docref) {
push @deprecated, "C<$name>" if $item->{flags} =~ /D/;
push @experimental, "C<$name>" if $item->{flags} =~ /x/;
push @back_compat, "C<$name>" if $item->{flags} =~ /B/;
+
+ # Find the visibility of this element. Also keep track of which
+ # element in the group has the longest name (for printf
+ # alignment). For later convenience, keep two lists, one gives
+ # the visibility for the element; the other is a list of elements
+ # that have a given visibility type
+ my $this_visibility;
+ my $length = length $name;
+ $visibility{longest_name} = $length
+ if $length > $visibility{longest_name};
+
+ if ($item->{flags} =~ /([CEeQ])/) {
+ $this_visibility = $visibility_name{$1};
+ }
+ elsif ($item->{flags} !~ /A/) {
+ $this_visibility = $visibility_name{e};
+ }
+ if ($this_visibility) {
+ push $visibility{by_type}{$this_visibility}->@*, $name;
+ $visibility{by_name}{$name} = $this_visibility;
+ }
}
# While we're going though the items, construct a nice list of where
@@ -2433,6 +2463,63 @@ sub docout ($fh, $section_name, $element_name, $docref) {
print $fh "\n=back\n";
}
+ if (defined $visibility{by_name}) {
+ print $fh "\nVisibility:";
+
+ # If there is only one type of visibility, output just it
+ if (keys $visibility{by_type}->%* == 1) {
+ print $fh " ", keys $visibility{by_type}->%*, "\n";
+ }
+ else {
+
+ # But if there is more than one, each element is listed separately
+ # with its visibility.
+ print $fh "\n\n=over 4\n\n";
+ my $most_items_count = 0;
+ my $most_items_type;
+
+ # Except if several symbols share the same type, group them all
+ # together as "Rest:". First find which type has the most symbols
+ # sharing it.
+ foreach my $type (keys $visibility{by_type}->%*) {
+ my $this_count = $visibility{by_type}{$type}->@*;
+ if ($this_count > $most_items_count) {
+ $most_items_type = $type;
+ $most_items_count = $this_count;
+ }
+ }
+
+ # If there aren't at least this many symbols in the type, it isn't
+ # worth separating out.
+ $most_items_type = "" if $most_items_count < 3;
+
+ # Now list every symbol in the group with its visibility.
+ foreach my $name (sort dictionary_order
+ keys $visibility{by_name}->%*)
+ {
+ my $type = $visibility{by_name}{$name};
+
+ # Skip this symbol if it is part of the remainder list
+ next if $type eq $most_items_type;
+
+ printf $fh " %-*s %s\n",
+ $visibility{longest_name} + 1,
+ "$name:",
+ $type;
+ }
+
+ # And output the remainder
+ if ($most_items_type) {
+ printf $fh " %-*s %s\n",
+ $visibility{longest_name} + 1,
+ "Rest:",
+ $most_items_type;
+ }
+
+ print $fh "\n=back\n";
+ }
+ }
+
print $fh "\n=back\n";
if (@where_froms) {
@@ -3205,8 +3292,46 @@ $intern{hdr} = <<"_EOB_";
|format but are not marked as part of the Perl API. In other words,
|B<they are not for use in extensions>!
-|It has the same sections as L<perlapi>, though some may be empty.
+|It has the same general form as L<perlapi>, though some sections may be
+|empty.
+|
+|Since the elements described here are not for general use, they may not even
+|be accessible to most or all XS modules. This accessibility is given at the
+|end of each group under the title "Visibility" with values as follows:
+|
+|=over 4
+|
+|=item $visibility_name{e}
+|
+|The element is not visible, and hence not accessible to code outside the Perl
+|core.
+|
+|=item $visibility_name{Q}
+|
+|The element is visible to the Perl core, and to the F<ext/re> modules, but
+|nowhere else.
+|
+|=item $visibility_name{E}
+|
+|The element is visible to the Perl core, and to any Perl extension, but
+|nowhere else. A module declares itself to be a Perl extension by including a
+|line like this in its source
+|
+| #define PERL_EXT
+|
+|=item $visibility_name{C}
+|
+|The element is actually accessible everywhere, even though it is not designed
+|for general use. A typical instance of this is when the element is a helper
+|function, macro, I<etc>., called in the expansion of an API macro.
+|
+|All such elements can be considered pollutants of the XS module's namespace.
+|See L<perlhacktips/Symbol visibility> for further discussion.
+|
+|=back
|
+|Since all API elements are always visible everywhere, there is no equivalent
+|of this visibility information in L<perlapi>.
_EOB_
$intern{footer} = <<"_EOE_";