diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 32c0135071468d3b6a818886267d73eb6ed38cc5..e54d46d62b18441bb1dd4c92d3a5df08b2674391 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -1548,15 +1548,7 @@ deparseFuncExpr(FuncExpr *node, deparse_expr_cxt *context)
 	procform = (Form_pg_proc) GETSTRUCT(proctup);
 
 	/* Check if need to print VARIADIC (cf. ruleutils.c) */
-	if (OidIsValid(procform->provariadic))
-	{
-		if (procform->provariadic != ANYOID)
-			use_variadic = true;
-		else
-			use_variadic = node->funcvariadic;
-	}
-	else
-		use_variadic = false;
+	use_variadic = node->funcvariadic;
 
 	/* Print schema name only if it's not pg_catalog */
 	if (procform->pronamespace != PG_CATALOG_NAMESPACE)
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 2b4ade0ffb315e72077bec3ff0e7a2195c57fb19..941b101f393fdd0a127303dc05f016f2faf5467d 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3152,9 +3152,10 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
      is zero based.  <function>get_call_result_type</> can also be used
      as an alternative to <function>get_fn_expr_rettype</>.
      There is also <function>get_fn_expr_variadic</>, which can be used to
-     find out whether the call contained an explicit <literal>VARIADIC</>
-     keyword.  This is primarily useful for <literal>VARIADIC "any"</>
-     functions, as described below.
+     find out whether variadic arguments have been merged into an array.
+     This is primarily useful for <literal>VARIADIC "any"</> functions,
+     since such merging will always have occurred for variadic functions
+     taking ordinary array types.
     </para>
 
     <para>
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 5934ab029757f9d59fd49b5c8e966ec5ffcc43c2..cc4608417b2c5b5c0ad6574903be7fd6dca28962 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -555,6 +555,17 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 	/* perform the necessary typecasting of arguments */
 	make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types);
 
+	/*
+	 * If the function isn't actually variadic, forget any VARIADIC decoration
+	 * on the call.  (Perhaps we should throw an error instead, but
+	 * historically we've allowed people to write that.)
+	 */
+	if (!OidIsValid(vatype))
+	{
+		Assert(nvargs == 0);
+		func_variadic = false;
+	}
+
 	/*
 	 * If it's a variadic function call, transform the last nvargs arguments
 	 * into an array --- unless it's an "any" variadic.
@@ -584,6 +595,11 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
 		newa->location = exprLocation((Node *) vargs);
 
 		fargs = lappend(fargs, newa);
+
+		/* We could not have had VARIADIC marking before ... */
+		Assert(!func_variadic);
+		/* ... but now, it's a VARIADIC call */
+		func_variadic = true;
 	}
 
 	/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 566b4c910b34a9a251c9f289115d1575faad1421..b1bac866aa16de30e2a3c73cb22c89bce5aea386 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -401,7 +401,7 @@ static char *get_relation_name(Oid relid);
 static char *generate_relation_name(Oid relid, List *namespaces);
 static char *generate_function_name(Oid funcid, int nargs,
 					   List *argnames, Oid *argtypes,
-					   bool was_variadic, bool *use_variadic_p);
+					   bool has_variadic, bool *use_variadic_p);
 static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
 static text *string_to_text(char *str);
 static char *flatten_reloptions(Oid relid);
@@ -8849,16 +8849,16 @@ generate_relation_name(Oid relid, List *namespaces)
  *
  * If we're dealing with a potentially variadic function (in practice, this
  * means a FuncExpr or Aggref, not some other way of calling a function), then
- * was_variadic must specify whether VARIADIC appeared in the original call,
+ * has_variadic must specify whether variadic arguments have been merged,
  * and *use_variadic_p will be set to indicate whether to print VARIADIC in
- * the output.	For non-FuncExpr cases, was_variadic should be FALSE and
+ * the output.	For non-FuncExpr cases, has_variadic should be FALSE and
  * use_variadic_p can be NULL.
  *
  * The result includes all necessary quoting and schema-prefixing.
  */
 static char *
 generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
-					   bool was_variadic, bool *use_variadic_p)
+					   bool has_variadic, bool *use_variadic_p)
 {
 	char	   *result;
 	HeapTuple	proctup;
@@ -8884,32 +8884,27 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
 	 * Determine whether VARIADIC should be printed.  We must do this first
 	 * since it affects the lookup rules in func_get_detail().
 	 *
-	 * Currently, we always print VARIADIC if the function is variadic and
-	 * takes a variadic type other than ANY.  (In principle, if VARIADIC
-	 * wasn't originally specified and the array actual argument is
-	 * deconstructable, we could print the array elements separately and not
-	 * print VARIADIC, thus more nearly reproducing the original input.  For
-	 * the moment that seems like too much complication for the benefit.)
-	 * However, if the function takes VARIADIC ANY, then the parser didn't
-	 * fold the arguments together into an array, so we must print VARIADIC if
-	 * and only if it was used originally.
+	 * Currently, we always print VARIADIC if the function has a merged
+	 * variadic-array argument.  Note that this is always the case for
+	 * functions taking a VARIADIC argument type other than VARIADIC ANY.
+	 *
+	 * In principle, if VARIADIC wasn't originally specified and the array
+	 * actual argument is deconstructable, we could print the array elements
+	 * separately and not print VARIADIC, thus more nearly reproducing the
+	 * original input.  For the moment that seems like too much complication
+	 * for the benefit, and anyway we do not know whether VARIADIC was
+	 * originally specified if it's a non-ANY type.
 	 */
 	if (use_variadic_p)
 	{
-		if (OidIsValid(procform->provariadic))
-		{
-			if (procform->provariadic != ANYOID)
-				use_variadic = true;
-			else
-				use_variadic = was_variadic;
-		}
-		else
-			use_variadic = false;
+		/* Parser should not have set funcvariadic unless fn is variadic */
+		Assert(!has_variadic || OidIsValid(procform->provariadic));
+		use_variadic = has_variadic;
 		*use_variadic_p = use_variadic;
 	}
 	else
 	{
-		Assert(!was_variadic);
+		Assert(!has_variadic);
 		use_variadic = false;
 	}
 
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index c7024b2225778ff469ee2892203b43eccfe91c34..1fe45da50ce2ce14c67921676dc9806da57e2463 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -2449,6 +2449,8 @@ get_call_expr_arg_stable(Node *expr, int argnum)
  * Get the VARIADIC flag from the function invocation
  *
  * Returns false (the default assumption) if information is not available
+ *
+ * Note this is generally only of interest to VARIADIC ANY functions
  */
 bool
 get_fn_expr_variadic(FmgrInfo *flinfo)
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 3c74fa0a5150bf9cc2c1bada1d696f8dad1ef344..e1a04c88b20bf2a61b5d5a43a47e4dd9ee10ae75 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201403261
+#define CATALOG_VERSION_NO	201404031
 
 #endif
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 4992bc083371ce2f53c83ef619dfd9a230f5fba4..9cce60b33be02e8a13bd2de94e5e16e88c106f11 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -257,7 +257,8 @@ typedef struct Aggref
 	List	   *aggdistinct;	/* DISTINCT (list of SortGroupClause) */
 	Expr	   *aggfilter;		/* FILTER expression, if any */
 	bool		aggstar;		/* TRUE if argument list was really '*' */
-	bool		aggvariadic;	/* TRUE if VARIADIC was used in call */
+	bool		aggvariadic;	/* true if variadic arguments have been
+								 * combined into an array last argument */
 	char		aggkind;		/* aggregate kind (see pg_aggregate.h) */
 	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
 	int			location;		/* token location, or -1 if unknown */
@@ -358,7 +359,8 @@ typedef struct FuncExpr
 	Oid			funcid;			/* PG_PROC OID of the function */
 	Oid			funcresulttype; /* PG_TYPE OID of result value */
 	bool		funcretset;		/* true if function returns set */
-	bool		funcvariadic;	/* true if VARIADIC was used in call */
+	bool		funcvariadic;	/* true if variadic arguments have been
+								 * combined into an array last argument */
 	CoercionForm funcformat;	/* how to display this function call */
 	Oid			funccollid;		/* OID of collation of result */
 	Oid			inputcollid;	/* OID of collation that function should use */