diff --git a/expand.c b/expand.c
index 60c6071..f7692bf 100644
--- a/expand.c
+++ b/expand.c
@@ -497,7 +497,7 @@ variable_append (const char *name, unsigned int length,
     return initialize_variable_output ();
 
   /* If this set is local and the next is not a parent, then next is local.  */
-  nextlocal = local && set->next_is_parent == 0;
+  nextlocal = local && set->mark != NEXT_IS_PARENT;
 
   /* Try to find the variable in this variable set.  */
   v = lookup_variable_in_set (name, length, set->set);
diff --git a/function.c b/function.c
index 8d8f198..09e9f99 100644
--- a/function.c
+++ b/function.c
@@ -2553,6 +2553,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
   int saved_args;
   const struct function_table_entry *entry_p;
   struct variable *v;
+  struct variable_set_list *setlist;
 
   /* Clean up the name of the variable to be invoked.  */
   fname = next_token (argv[0]);
@@ -2594,7 +2595,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
 
   /* Set up arguments $(1) .. $(N).  $(0) is the function name.  */
 
-  push_new_variable_scope ();
+  setlist = push_new_variable_scope ();
 
   for (i=0; *argv; ++i, ++argv)
     {
@@ -2604,31 +2605,28 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
       define_variable (num, strlen (num), *argv, o_automatic, 0);
     }
 
-  /* If the number of arguments we have is < max_args, it means we're inside
-     a recursive invocation of $(call ...).  Fill in the remaining arguments
-     in the new scope with the empty value, to hide them from this
-     invocation.  */
-
-  for (; i < max_args; ++i)
-    {
-      char num[11];
+  /* Adjust max_args - the maximum number of arguments among calls of
+     user-defined functions in the call stack up to and including this
+     $(call ...) invocation.  */
+  saved_args = max_args;
+  if (i > max_args)
+    max_args = i;
 
-      sprintf (num, "%d", i);
-      define_variable (num, strlen (num), "", o_automatic, 0);
-    }
+  /* Mark the list with max_args - the mark is checked while looking up
+     variables in outer scope: if variable name looks like user-defined
+     function call argument, e.g. $(123), and it's decimal value is less
+     than the mark, then the variable must not be found.  */
+  setlist->mark = max_args;
 
   /* Expand the body in the context of the arguments, adding the result to
      the variable buffer.  */
 
   v->exp_count = EXP_COUNT_MAX;
-
-  saved_args = max_args;
-  max_args = i;
   o = variable_expand_string (o, body, flen+3);
-  max_args = saved_args;
-
   v->exp_count = 0;
 
+  max_args = saved_args;
+
   pop_variable_scope ();
 
   return o + strlen (o);
diff --git a/variable.c b/variable.c
index 364774f..b92153d 100644
--- a/variable.c
+++ b/variable.c
@@ -465,6 +465,7 @@ lookup_variable (const char *name, unsigned int length)
   const struct variable_set_list *setlist;
   struct variable var_key;
   int is_parent = 0;
+  int maybe_argument = 1;
 
   var_key.name = (char *) name;
   var_key.length = length;
@@ -479,7 +480,45 @@ lookup_variable (const char *name, unsigned int length)
       if (v && (!is_parent || !v->private_var))
         return v->special ? lookup_special_var (v) : v;
 
-      is_parent |= setlist->next_is_parent;
+      /* Variable was not found.  Check if it looks like function call
+         argument: $1,$2,$3...  If it is and we are in the context of user
+         function call, then we must not take arguments of outer functions.  */
+
+      if (setlist->mark == NEXT_IS_PARENT)
+        is_parent = 1;
+      else if (setlist->mark && maybe_argument)
+        {
+          /* Argument $0 is always defined and must be found,
+             names of other arguments do not begin with '0' */
+          if ('0' != *name)
+            {
+              /* Try to parse decimal number.  Check for integer overflow.
+                 If parsing failed or the number is greater or equal to the
+                 maximum number of arguments among calls of user-defined
+                 functions in the call stack, then the variable is not a
+                 function argument.  */
+              int number = 0, a;
+              int m = setlist->mark/10;
+              unsigned int i;
+              for (i = 0; i < length; i++)
+                {
+                  if (!ISDIGIT(name[i]))
+                    break;
+                  if (number > m)
+                    break;
+                  number *= 10;
+                  a = name[i] - '0';
+                  if (a >= setlist->mark - number)
+                    break;
+                  number += a;
+                }
+
+              if (i == length)
+                return 0;
+            }
+
+          maybe_argument = 0;
+        }
     }
 
 #ifdef VMS
@@ -590,7 +629,7 @@ initialize_file_variables (struct file *file, int reading)
     {
       initialize_file_variables (file->double_colon, reading);
       l->next = file->double_colon->variables;
-      l->next_is_parent = 0;
+      l->mark = 0;
       return;
     }
 
@@ -601,7 +640,7 @@ initialize_file_variables (struct file *file, int reading)
       initialize_file_variables (file->parent, reading);
       l->next = file->parent->variables;
     }
-  l->next_is_parent = 1;
+  l->mark = NEXT_IS_PARENT;
 
   /* If we're not reading makefiles and we haven't looked yet, see if
      we can find pattern variables for this target.  */
@@ -661,9 +700,9 @@ initialize_file_variables (struct file *file, int reading)
   if (file->pat_variables != 0)
     {
       file->pat_variables->next = l->next;
-      file->pat_variables->next_is_parent = l->next_is_parent;
+      file->pat_variables->mark = l->mark;
       l->next = file->pat_variables;
-      l->next_is_parent = 0;
+      l->mark = 0;
     }
 }
 
@@ -684,7 +723,7 @@ create_new_variable_set (void)
     xmalloc (sizeof (struct variable_set_list));
   setlist->set = set;
   setlist->next = current_variable_set_list;
-  setlist->next_is_parent = 0;
+  setlist->mark = 0;
 
   return setlist;
 }
@@ -706,9 +745,11 @@ push_new_variable_scope (void)
          pointing to &global  */
       struct variable_set *set = current_variable_set_list->set;
       current_variable_set_list->set = global_setlist.set;
-      global_setlist.set = set;
       current_variable_set_list->next = global_setlist.next;
+      current_variable_set_list->mark = global_setlist.mark;
+      global_setlist.set = set;
       global_setlist.next = current_variable_set_list;
+      global_setlist.mark = 0;
       current_variable_set_list = &global_setlist;
     }
   return (current_variable_set_list);
@@ -739,7 +780,7 @@ pop_variable_scope (void)
       set = global_setlist.set;
       global_setlist.set = setlist->set;
       global_setlist.next = setlist->next;
-      global_setlist.next_is_parent = setlist->next_is_parent;
+      global_setlist.mark = setlist->mark;
     }
 
   /* Free the one we no longer need.  */
diff --git a/variable.h b/variable.h
index a36e147..dd75954 100644
--- a/variable.h
+++ b/variable.h
@@ -94,7 +94,19 @@ struct variable_set_list
   {
     struct variable_set_list *next;     /* Link in the chain.  */
     struct variable_set *set;           /* Variable set.  */
-    int next_is_parent;                 /* True if next is a parent target.  */
+
+    /* Mark of the list:
+      -1 - next is a parent target;
+       0 - list is not marked;
+      >0 - variable set of the list contains arguments of user-defined function
+           call.  Mark value - is the maximum number of arguments among calls
+           of user-defined functions in the call stack up to and including this
+           list.  Function name (passed as $0 argument) is always counted, so
+           number of arguments cannot be zero.  */
+
+#define NEXT_IS_PARENT -1
+
+    int mark;
   };
 
 /* Structure used for pattern-specific variables.  */
