Index: flang/lib/Parser/preprocessor.cpp =================================================================== --- flang/lib/Parser/preprocessor.cpp +++ flang/lib/Parser/preprocessor.cpp @@ -288,6 +288,7 @@ result.Put(input, j); continue; } + auto dirName{token.ToString()}; Definition *def{&it->second}; if (def->isDisabled()) { result.Put(input, j); @@ -332,6 +333,7 @@ auto it{definitions_.find(token)}; if (it != definitions_.end() && !it->second.isDisabled() && it->second.isFunctionLike()) { + dirName = token.ToString(); def = &it->second; isRenaming = true; } @@ -385,6 +387,21 @@ } if (k >= tokens || argStart.size() < def->argumentCount() || (argStart.size() > def->argumentCount() && !def->isVariadic())) { + if (k >= tokens) { + prescanner.Say(input.GetTokenProvenance(j), + "unterminated argument list invoking macro '%s'"_err_en_US, + dirName); + } else if (argStart.size() < def->argumentCount()) { + // FIXME: argStart is never zero if def->argumentCount() > 0 + // so this will at least diagnose "but only 1 given". + prescanner.Say(input.GetTokenProvenance(j), + "macro '%s' requires %d arguments, but only %d given"_err_en_US, + dirName, def->argumentCount(), argStart.size()); + } else if (argStart.size() > def->argumentCount()) { + prescanner.Say(input.GetTokenProvenance(j), + "macro '%s' passed %d arguments, but takes just %d"_err_en_US, + dirName, argStart.size(), def->argumentCount()); + } result.Put(input, j); continue; } Index: flang/test/Preprocessing/diag-macro1.F90 =================================================================== --- /dev/null +++ flang/test/Preprocessing/diag-macro1.F90 @@ -0,0 +1,17 @@ +! RUN: not %flang -E %s 2>&1 | FileCheck %s +! Check that we diagnose wrong arguments passed to function-like macros. +subroutine foo() + implicit none + +#define sub(x, y) foo2(x, y) +#define sub0() foo2(1, 2) + call sub() + call sub(1) + call sub(1, 2, 3) + call sub0(1, 2) +end subroutine foo + +!CHECK: error: macro 'sub' requires 2 arguments, but only 1 given +!CHECK: error: macro 'sub' requires 2 arguments, but only 1 given +!CHECK: error: macro 'sub' passed 3 arguments, but takes just 2 +!CHECK: error: macro 'sub0' passed 2 arguments, but takes just 0 Index: flang/test/Preprocessing/diag-macro2.F90 =================================================================== --- /dev/null +++ flang/test/Preprocessing/diag-macro2.F90 @@ -0,0 +1,10 @@ +! RUN: not %flang -E %s 2>&1 | FileCheck %s +! Check that we diagnose unterminated function-like macro invocations +subroutine foo() + implicit none +#define sub(x, y) foo2(x, y) + call sub(1, 2 + print *, "hello" +end subroutine foo + +!CHECK: error: unterminated argument list invoking macro 'sub' Index: flang/test/Preprocessing/diag-macro3.F90 =================================================================== --- /dev/null +++ flang/test/Preprocessing/diag-macro3.F90 @@ -0,0 +1,11 @@ +! RUN: not %flang -E %s 2>&1 | FileCheck %s +! Check that we diagnose unterminated function-like macro invocations +subroutine foo() + implicit none +#define sub(x, y) foo2(x, y) +#define bar ) + call sub(1, 2 bar + print *, "hello" +end subroutine foo + +!CHECK: error: unterminated argument list invoking macro 'sub' Index: flang/test/Preprocessing/diag-macro4.F90 =================================================================== --- /dev/null +++ flang/test/Preprocessing/diag-macro4.F90 @@ -0,0 +1,20 @@ +! RUN: not %flang -E %s 2>&1 | FileCheck %s +! Check that we diagnose wrong arguments passed to function-like macros, +! this time indirectly using another object-like macro. +subroutine foo() + implicit none + +#define presub sub +#define presub0 sub0 +#define sub(x, y) foo2(x, y) +#define sub0() foo2(1, 2) + call presub() + call presub(1) + call presub(1, 2, 3) + call presub0(1, 2) +end subroutine foo + +!CHECK: error: macro 'sub' requires 2 arguments, but only 1 given +!CHECK: error: macro 'sub' requires 2 arguments, but only 1 given +!CHECK: error: macro 'sub' passed 3 arguments, but takes just 2 +!CHECK: error: macro 'sub0' passed 2 arguments, but takes just 0