* automake.in (conditional_true_when): Return false if $WHEN == FALSE.
authorAlexandre Duret-Lutz <adl@gnu.org>
Thu, 16 May 2002 20:36:36 +0000 (20:36 +0000)
committerAlexandre Duret-Lutz <adl@gnu.org>
Thu, 16 May 2002 20:36:36 +0000 (20:36 +0000)
(conditional_is_redundant): Simplify.
(conditional_implies_one_of,
variable_not_always_defined_in_cond): New functions
(macro_define): Reject appends if the variable is not defined in
all conditions where `+=' applies.
(invert_conditions): Rewrite.  Before this patch,
invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE")
would return ("A_FALSE B_TRUE", "A_FALSE B_TRUE"), which seems
wrong (these conditions implies "A_FALSE").  Now it outputs (),
which just means the input conditions cover all cases.
(variable_conditions_permutations): Never output FALSE conditions.
* tests/pluseq2.test, tests/pluseq3.test: Define data_DATA
in the CHECK_FALSE condition to fix the test.
* tests/pluseq5.test: Actually check the diagnostic.
* tests/pluseq9.test: New file.
* tests/Makefile.am (TESTS): Add pluseq9.test.

ChangeLog
automake.in
tests/Makefile.am
tests/Makefile.in
tests/pluseq2.test
tests/pluseq3.test
tests/pluseq5.test
tests/pluseq9.test [new file with mode: 0755]

index 15ac16d..3fb5902 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2002-05-16  Alexandre Duret-Lutz  <duret_g@epita.fr>
+
+       * automake.in (conditional_true_when): Return false if $WHEN == FALSE.
+       (conditional_is_redundant): Simplify.
+       (conditional_implies_one_of,
+       variable_not_always_defined_in_cond): New functions
+       (macro_define): Reject appends if the variable is not defined in
+       all conditions where `+=' applies.
+       (invert_conditions): Rewrite.  Before this patch,
+       invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE")
+       would return ("A_FALSE B_TRUE", "A_FALSE B_TRUE"), which seems
+       wrong (these conditions implies "A_FALSE").  Now it outputs (),
+       which just means the input conditions cover all cases.
+       (variable_conditions_permutations): Never output FALSE conditions.
+       * tests/pluseq2.test, tests/pluseq3.test: Define data_DATA
+       in the CHECK_FALSE condition to fix the test.
+       * tests/pluseq5.test: Actually check the diagnostic.
+       * tests/pluseq9.test: New file.
+       * tests/Makefile.am (TESTS): Add pluseq9.test.
+
 2002-05-14  Alexandre Duret-Lutz  <duret_g@epita.fr>
 
        Fix for PR automake/322:
index bf252a1..f6cb007 100755 (executable)
@@ -5351,6 +5351,10 @@ sub conditional_true_when ($$)
     # Make a hash holding all the values from $WHEN.
     my %cond_vals = map { $_ => 1 } split (' ', $when);
 
+    # Nothing is true when FALSE (not even FALSE itself, but it
+    # shouldn't hurt if you decide to change that).
+    return 0 if exists $cond_vals{'FALSE'};
+
     # Check each component of $cond, which looks `COND1 COND2'.
     foreach my $comp (split (' ', $cond))
     {
@@ -5376,18 +5380,30 @@ sub conditional_is_redundant ($@)
 {
     my ($cond, @whens) = @_;
 
-    if (@whens == 0)
+    @whens = ("") if @whens == 0;
+
+    foreach my $when (@whens)
     {
-       return 1 if conditional_true_when ($cond, "");
+       return 1 if conditional_true_when ($cond, $when);
     }
-    else
+    return 0;
+}
+
+
+# $BOOLEAN
+# &conditional_implies_one_of ($COND, @CONDS)
+# -------------------------------------------
+# Returns true iff $COND implies one of the conditions in @CONDS.
+sub conditional_implies_one_of ($@)
+{
+    my ($cond, @conds) = @_;
+
+    @conds = ("") if @conds == 0;
+
+    foreach my $c (@conds)
     {
-       foreach my $when (@whens)
-       {
-           return 1 if conditional_true_when ($cond, $when);
-       }
+       return 1 if conditional_true_when ($c, $cond);
     }
-
     return 0;
 }
 
@@ -5618,6 +5634,85 @@ sub conditional_ambiguous_p ($$)
     return '';
 }
 
+# @MISSING_CONDS
+# variable_not_always_defined_in_cond ($VAR, $COND)
+# ---------------------------------------------
+# Check whether $VAR is always defined for condition $COND.
+# Return a list of conditions where the definition is missing.
+#
+# For instance, given
+#
+#   if COND1
+#     if COND2
+#       A = foo
+#       D = d1
+#     else
+#       A = bar
+#       D = d2
+#     endif
+#   else
+#     D = d3
+#   endif
+#   if COND3
+#     A = baz
+#     B = mumble
+#   endif
+#   C = mumble
+#
+# we should have:
+#   variable_not_always_defined_in_cond ('A', 'COND1_TRUE COND2_TRUE')
+#     => ()
+#   variable_not_always_defined_in_cond ('A', 'COND1_TRUE')
+#     => ()
+#   variable_not_always_defined_in_cond ('A', 'TRUE')
+#     => ("COND1_FALSE COND2_FALSE COND3_FALSE",
+#         "COND1_FALSE COND2_TRUE COND3_FALSE",
+#         "COND1_TRUE COND2_FALSE COND3_FALSE",
+#         "COND1_TRUE COND2_TRUE COND3_FALSE")
+#   variable_not_always_defined_in_cond ('B', 'COND1_TRUE')
+#     => ("COND3_FALSE")
+#   variable_not_always_defined_in_cond ('C', 'COND1_TRUE')
+#     => ()
+#   variable_not_always_defined_in_cond ('D', 'TRUE')
+#     => ()
+#   variable_not_always_defined_in_cond ('Z', 'TRUE')
+#     => ("TRUE")
+#
+sub variable_not_always_defined_in_cond ($$)
+{
+    my ($var, $cond) = @_;
+
+    # It's easy to answer if the variable is not defined.
+    return ("TRUE",) unless exists $var_value{$var};
+
+    # How does it work?  Let's take the second example:
+    #
+    #   variable_not_always_defined_in_cond ('A', 'COND1_TRUE')
+    #
+    # (1) First, we get the list of conditions where A is defined:
+    #
+    #   ("COND1_TRUE COND2_TRUE", "COND1_TRUE COND2_FALSE", "COND3_TRUE")
+    #
+    # (2) Then we generate the set of inverted conditions:
+    #
+    #   ("COND1_FALSE COND2_TRUE COND3_FALSE",
+    #    "COND1_FALSE COND2_FALSE COND3_FALSE")
+    #
+    # (3) Finally we remove these conditions which are not implied by
+    #     COND1_TRUE.  This yields an empty list and we are done.
+
+    my @res = ();
+    my @cond_defs = keys %{$var_value{$var}}; # (1)
+    foreach my $icond (invert_conditions (@cond_defs)) # (2)
+    {
+       prog_error ("invert_conditions returned an input condition")
+           if exists $var_value{$var}{$icond};
+
+       push @res, $icond
+           if (conditional_true_when ($cond, $icond)); # (3)
+    }
+    return @res;
+}
 
 # &macro_define($VAR, $VAR_IS_AM, $TYPE, $COND, $VALUE, $WHERE)
 # -------------------------------------------------------------
@@ -5727,7 +5822,29 @@ sub macro_define ($$$$$$)
       # Add VALUE to all definitions of VAR.
       foreach my $vcond (keys %{$var_value{$var}})
         {
-           &macro_define ($var, $var_is_am, '+', $vcond, $value, $where);
+         # We have a bit of error detection to do here.
+         # This:
+         #   if COND1
+         #     X = Y
+         #   endif
+         #   X += Z
+         # should be rejected because X is not defined for all conditions
+         # where `+=' applies.
+         my @undef_cond = variable_not_always_defined_in_cond $var, $cond;
+         if (@undef_cond != 0)
+           {
+             file_error ($where,
+                         "Cannot apply `+=' because `$var' is not defined "
+                         . "in\nthe following conditions:\n  "
+                         . join ("\n  ", @undef_cond)
+                         . "\nEither define `$var' in these conditions,"
+                         . " or use\n`+=' in the same conditions as"
+                         . " the definitions.");
+           }
+         else
+           {
+             &macro_define ($var, $var_is_am, '+', $vcond, $value, $where);
+           }
        }
     }
   # 3. first assignment (=, :=, or +=)
@@ -5933,6 +6050,7 @@ sub variable_conditions_recursive ($)
     %vars_scanned = ();
 
     my @new_conds = variable_conditions_recursive_sub ($var, '');
+
     # Now we want to return all permutations of the subvariable
     # conditions.
     my %allconds = ();
@@ -6131,25 +6249,49 @@ sub variable_conditions_reduce
 # are never true for any of the input conditionals, and when taken
 # together with the input conditionals cover all possible cases.
 #
-# For example: invert_conditions("A_TRUE B_TRUE", "A_FALSE B_FALSE") will
-# return ("A_FALSE B_TRUE", "A_TRUE B_FALSE")
+# For example:
+#   invert_conditions("A_TRUE B_TRUE", "A_FALSE B_FALSE")
+#     => ("A_FALSE B_TRUE", "A_TRUE B_FALSE")
+#
+#   invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE")
+#     => ()
 sub invert_conditions
 {
     my (@conds) = @_;
 
     my @notconds = ();
-    foreach my $cond (@conds)
+
+    # Generate all permutation for all inputs.
+    my @perm =
+       map { variable_conditions_permutations (split(' ', $_)); } @conds;
+    # Remove redundant conditions.
+    @perm = variable_conditions_reduce @perm;
+
+    # Now remove all conditions which imply one of the input conditions.
+    foreach my $perm (@perm)
     {
-       foreach my $perm (variable_conditions_permutations (split(' ', $cond)))
-       {
-           push @notconds, $perm
-                   if ! conditional_is_redundant ($perm, @conds);
-       }
+       push @notconds, $perm
+           if ! conditional_implies_one_of ($perm, @conds);
     }
-    return variable_conditions_reduce (@notconds);
+    return @notconds;
 }
 
 # Return a list of permutations of a conditional string.
+# (But never output FALSE conditions, they are useless.)
+#
+# Examples:
+#   variable_conditions_permutations ("FOO_FALSE", "BAR_TRUE")
+#     => ("FOO_FALSE BAR_FALSE",
+#         "FOO_FALSE BAR_TRUE",
+#         "FOO_TRUE BAR_FALSE",
+#         "FOO_TRUE BAR_TRUE")
+#   variable_conditions_permutations ("FOO_FALSE", "TRUE")
+#     => ("FOO_FALSE TRUE",
+#         "FOO_TRUE TRUE")
+#   variable_conditions_permutations ("TRUE")
+#     => ("TRUE")
+#   variable_conditions_permutations ("FALSE")
+#     => ("TRUE")
 sub variable_conditions_permutations
 {
     my (@comps) = @_;
@@ -6163,13 +6305,13 @@ sub variable_conditions_permutations
     my @ret;
     foreach my $sub (variable_conditions_permutations (@comps))
     {
-       push (@ret, "$comp $sub");
-       push (@ret, "$neg $sub");
+       push (@ret, "$comp $sub") if $comp ne 'FALSE';
+       push (@ret, "$neg $sub") if $neg ne 'FALSE';
     }
     if (! @ret)
     {
-       push (@ret, $comp);
-       push (@ret, $neg);
+       push (@ret, $comp) if $comp ne 'FALSE';
+       push (@ret, $neg) if $neg ne 'FALSE';
     }
     return @ret;
 }
index 837a13f..33e5ed4 100644 (file)
@@ -254,6 +254,7 @@ pluseq5.test \
 pluseq6.test \
 pluseq7.test \
 pluseq8.test \
+pluseq9.test \
 postproc.test \
 ppf77.test \
 pr2.test \
index 12618e1..45b4f2a 100644 (file)
@@ -338,6 +338,7 @@ pluseq5.test \
 pluseq6.test \
 pluseq7.test \
 pluseq8.test \
+pluseq9.test \
 postproc.test \
 ppf77.test \
 pr2.test \
index be1e070..90626f8 100755 (executable)
@@ -10,6 +10,8 @@ cat > Makefile.am << 'END'
 
 if CHECK
 data_DATA = zar
+else
+data_DATA =
 endif
 
 if CHECK
index 58555a6..7177801 100755 (executable)
@@ -10,6 +10,8 @@ cat > Makefile.am << 'END'
 
 if CHECK
 data_DATA = zar
+else
+data_DATA =
 endif
 
 if CHECK
index e1d4903..6009e5e 100755 (executable)
@@ -14,5 +14,21 @@ INCLUDES += def
 END
 
 $ACLOCAL || exit 1
-$AUTOMAKE || exit 0
-exit 1
+$AUTOMAKE 2>stderr && exit 1
+
+cat stderr # for debugging
+
+# We expect the following diagnostic:
+#
+# Makefile.am:4: Cannot apply `+=' because `INCLUDES' is not defined in
+# Makefile.am:4: the following conditions:
+# Makefile.am:4:   CHECK_FALSE
+# Makefile.am:4: Either define `INCLUDES' in these conditions, or use
+# Makefile.am:4: `+=' in the same conditions as the definitions.
+
+# Is CHECK_FALSE mentioned?
+grep ':.*CHECK_FALSE$' stderr || exit 1
+# Is there only one missing condition?
+test `grep ':  ' stderr | wc -l` = 1 || exit 1
+
+:
diff --git a/tests/pluseq9.test b/tests/pluseq9.test
new file mode 100755 (executable)
index 0000000..2aed68f
--- /dev/null
@@ -0,0 +1,60 @@
+#! /bin/sh
+
+# Test the += diagnostics.
+
+. $srcdir/defs || exit 1
+
+cat >>configure.in <<EOF
+AM_CONDITIONAL(COND1, true)
+AM_CONDITIONAL(COND2, true)
+AM_CONDITIONAL(COND3, true)
+EOF
+
+cat > Makefile.am << 'END'
+if COND1
+if COND2
+    A = a
+    B = aa
+else
+    A = b
+    B = bb
+endif
+  A += c
+else
+  A = d
+endif
+A += e
+
+if COND3
+  A += f
+  B = cc
+endif
+B += dd
+END
+
+$ACLOCAL || exit 1
+$AUTOMAKE 2>stderr && exit 1
+
+cat stderr # for debugging
+
+# We expect the following diagnostic:
+#
+# Makefile.am:19: Cannot apply `+=' because `B' is not defined in
+# Makefile.am:19: the following conditions:
+# Makefile.am:19:   COND3_FALSE
+# Makefile.am:19:   COND1_FALSE COND2_FALSE
+# Makefile.am:19:   COND1_FALSE COND2_TRUE
+# Makefile.am:19: Either define `B' in these conditions, or use
+# Makefile.am:19: `+=' in the same conditions as the definitions.
+#
+# It would be nice if Automake could print only COND3_FALSE and
+# COND1_FALSE (merging the last two conditions), so we'll support
+# this case in the check too.
+
+# Are COND3_FALSE and COND1_FALSE mentioned?
+grep ':.*COND3_FALSE$' stderr || exit 1
+grep ':.*COND1_FALSE' stderr || exit 1
+# Make sure there are no more than three missing conditions.
+test `grep ':  ' stderr | wc -l` -le 3 || exit 1
+
+: