Skip to content

Commit af4bdf8

Browse files
committed
Macros guarded by some #ifdef's aren't globally visible
The previous commit undefines macros that aren't supposed to be visible to XS code. But, to avoid any possible breakage, it creates an exception list of symbols that may have been visible, and leaves them so. The goal is to stop the list from growing as new code is developed, and to shorten the list by various means. This is the first commit to do that, by looking to see if any symbols aren't actually externally visible because they are guarded by #ifdef's that evaluate to false. For example a symbol that is #defined only if PERL_CORE is defined won't be visible, and need not be on the exception list. This cuts almost 30% off the initial list.
1 parent bc869bf commit af4bdf8

File tree

2 files changed

+205
-1548
lines changed

2 files changed

+205
-1548
lines changed

regen/HeaderParser.pm

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,169 @@ sub _best_path {
13041304
return ($best, $rest);
13051305
}
13061306

1307+
sub HeaderLine::reduce_conds {
1308+
1309+
# Reduce the preprocessor conditionals that guard the HeaderLine $self
1310+
# object, given a hash that says the values of certain preprocessor
1311+
# conditions, and a corresponding regular expression pattern that matches
1312+
# any of those conditions.
1313+
#
1314+
# This currently returns 0 if the conditionals as a whole evaluate to
1315+
# false; and 1 if they might evaluate to true.
1316+
1317+
my ($self, $constraints_pat, $constraints_ref) = @_;
1318+
1319+
# Short cut the common case of there being no conditions in effect.
1320+
return 1 if $self->{cond}->@* == 0;
1321+
1322+
# We need a copy so we don't destroy the input.
1323+
my @cond = copy_aoa($self->{cond}->@*);
1324+
1325+
return _reduce_conds(\@cond, $constraints_pat, $constraints_ref);
1326+
}
1327+
1328+
sub _reduce_conds {
1329+
my ($cond_ref, $constraints_pat, $constraints_ref, $recursed) = @_;
1330+
1331+
# This does the heavy lifting for HeaderLine::reduce_conds(). It
1332+
# recursively descends the array $cond_ref of conditions. These have been
1333+
# normalized by HeaderParser so that each element is ANDed with all the
1334+
# other ones. Hence if any element evaluates to false, the whole array
1335+
# must.
1336+
#
1337+
# Each leaf node will have a series of conditionals (typically linked by
1338+
# '||') , each of which has been normalized by HeaderParser to look like
1339+
# either of;
1340+
# defined(foo)
1341+
# !defined(foo)
1342+
# All the ones of these that match $constraints_pat are substituted by
1343+
# their corresponding value in %constraints_ref, which will be either 0 or
1344+
# 1. The result is looked at to see if it has to evaluate to 0 or not.
1345+
1346+
# At leaf nodes, just change all defined(foo) whose values of foo are
1347+
# known to be those values, reducing them to "#if 0" or "#if 1".
1348+
if (ref $cond_ref ne "ARRAY") {
1349+
die "Expecting an array at top-level call" unless $recursed;
1350+
1351+
$cond_ref =~ s/$constraints_pat/$constraints_ref->{$1}/g;
1352+
reduce_ones_and_zeros(\$cond_ref);
1353+
1354+
# Assume 1 if doesn't evaluate completely to 0.
1355+
return $cond_ref ne '0';
1356+
}
1357+
1358+
# Here, the conditions are in an array. We recurse to handle each
1359+
# element of the array.
1360+
for my $cond ($cond_ref->@*) {
1361+
return 0 unless _reduce_conds($cond,
1362+
$constraints_pat,
1363+
$constraints_ref,
1364+
($recursed // 0) + 1 # is recursed
1365+
);
1366+
}
1367+
1368+
# Didn't do an early return. Nothing conclusively evaluated to 0.
1369+
return 1;
1370+
}
1371+
1372+
sub reduce_ones_and_zeros {
1373+
my $ref = shift;
1374+
1375+
# This reduces as much as possible a symbolic C preprocessor expression
1376+
# that hopefully has terms that are either 0 or 1. We know that anything
1377+
# ANDed with 0 is 0 and anything OR'd with 1 is 1, for example. By
1378+
# repeating these and other rules, until nothing more changes, we reduce
1379+
# it as much as possible, given what is known. In many cases that this is
1380+
# called in, the value gets down to simply 0 or 1.
1381+
#
1382+
# This is simplistic, not knowing about precedence, for example. khw took
1383+
# it from Devel::PPPort. But it works well enough. HeaderParser could be
1384+
# enlisted to make it work better.
1385+
my $any_changed = 0;
1386+
1387+
if (ref $ref eq 'ARRAY') {
1388+
foreach my $element ($ref->@*) {
1389+
$any_changed |= reduce_ones_and_zeros(\$element)
1390+
if $element =~ / ^ # \s* (?: if | el ) /x;
1391+
}
1392+
1393+
return $any_changed;
1394+
}
1395+
1396+
my $changed;
1397+
do {
1398+
$changed = 0;
1399+
1400+
# (0) -> 0
1401+
$changed |= $$ref =~ s/ \( \s* 0 \s* \) /0/xg;
1402+
1403+
# !0 -> 1
1404+
$changed |= $$ref =~ s/ ! \s* 0 \b /1/xg;
1405+
1406+
# '|| 0 ||' -> ||
1407+
$changed |= $$ref =~ s/ \s* \|\| \s* 0 \s* \|\| /||/xg;
1408+
1409+
# '^ 0 || foo' -> foo
1410+
# '(0 || foo' -> (foo
1411+
$changed |= $$ref =~ s/ ^ \s* 0 \s* \|\| \s* //xg;
1412+
$changed |= $$ref =~ s/ \( \s* 0 \s* \|\| \s* /(/xg;
1413+
1414+
# 'foo || 0 ) ' -> foo
1415+
# 'foo || 0 $ ' -> foo
1416+
$changed |= $$ref =~ s/ \s* \|\| \s* 0 \s* (?= $ | \) ) //xg;
1417+
1418+
# '^ 0 && foo' doesn't work because of precedence: '0 && anything || 1'
1419+
# Similarly for 'foo && 0 $'
1420+
1421+
# (1) -> 1
1422+
$changed |= $$ref =~ s/ \( \s* 1 \s* \) /1/xg;
1423+
1424+
# !1 -> 0
1425+
$changed |= $$ref =~ s/ ! \s* 1 \b /0/xg;
1426+
1427+
# '&& 1 &&' -> &&
1428+
$changed |= $$ref =~ s/ \s* && \s* 1 \s* && /&&/xg;
1429+
1430+
# '^ 1 && foo' -> foo
1431+
# '^ 1 || foo' -> 1 # Works cause || lower precedence than &&
1432+
$changed |= $$ref =~ s/ ^ \s* 1 \s* && \s* //xg;
1433+
#$changed |= $$ref =~ s/ ^ \s* 1 \s* \|\| .* /1/xg;
1434+
1435+
# '(1 && foo' -> (foo
1436+
$changed |= $$ref =~ s/ \( \s* 1 \s* && \s* /(/xg;
1437+
1438+
# 'foo && 1 [ )$ ] ' -> foo
1439+
$changed |= $$ref =~ s/ \s* && \s* 1 \s* (?= $ | \) ) //xg;
1440+
1441+
# There are other things that could be reduced, but looking for
1442+
# just the defined(foo) case doesn't involve fancy parsing,
1443+
# and catches just about everything
1444+
1445+
# 'defined(foo) && 0' -> 0
1446+
$changed |= $$ref
1447+
=~ s/ (?: ! \s*)? \b defined \s* \(\w+\)
1448+
\s* && \s* 0 \b /0/xg;
1449+
1450+
# 'defined(foo) || 1' -> 1
1451+
$changed |= $$ref
1452+
=~ s/ (?: ! \s*)? \b defined \s* \(\w+\)
1453+
\s* \|\| \s* 1 \b /1/xg;
1454+
1455+
# '0 && defined(foo)' -> 0
1456+
$changed |= $$ref
1457+
=~ s/ \b 0 \s* && \s* (?: ! \s*)? defined
1458+
\s* \(\w+\) /0/xg;
1459+
1460+
# '1 || defined(foo)' -> 1
1461+
$changed |= $$ref
1462+
=~ s/ \b 1 \s* \|\| \s* (?: ! \s*)? defined
1463+
\s* \(\w+\) /1/xg;
1464+
$any_changed |= $changed;
1465+
} while ($changed);
1466+
1467+
return $any_changed;
1468+
}
1469+
13071470
# This builds a group content tree from a set of lines. each content line in
13081471
# the original file is added to the file based on the conditions that apply to
13091472
# the content.

0 commit comments

Comments
 (0)