From running GNU Make 3.82 in a debugger: For target "foo", pattern_search() treats "$(PREREQS)" as one word not equal to "|", and therefore does not set the order-only flag. Instead, it applies second expansion to produce "p1|p2". It then invokes PARSE_FILE_SEQ, which stops at '|', but the fact that "|p2" remains unparsed goes unnoticed. For target "bar", pattern_search() treats "p1|$(P2)" as two words: "p1|" and "$(P2)", neither equal to "|". Note the significance of the absence of space before '|'. The first word gets second-expanded trivially and then split into "p1", ignoring the leftover "|". The second gets second-expanded into p2, which is treated as a normal prerequisite because the '|' was ignored. The comparison of words against "|" before second expansion seems both unnecessary and insufficient. Would it be better to check the results of PARSE_FILE_SEQ, to see if it stopped because it found a '|'?