Skip to content

Commit b95f28f

Browse files
committed
Merge branch 'topic/419-prepro-comments' into 'master'
Instrument.C: Fix pre-processing of sources where comments cannot be preserved Closes #419 See merge request eng/das/cov/gnatcoverage!846 Some macros can perform token concatenation, but do not allow concatenating comments with other tokens. The comments are normally replaced by white spaces before macro expansion, but gnatcov needs to preserve comments to process annotations. In this case the pre-processor will error out when asked to preserve the comments. To fix this, this change introduces a retry without the -C argument. This allows gnatcov to properly instrument the source, but annotations will be ignored. Closes eng/das/cov/gnatcoverage#419
2 parents 1c04811 + 36db09a commit b95f28f

File tree

6 files changed

+139
-11
lines changed

6 files changed

+139
-11
lines changed

doc/gnatcov/src_traces.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,13 @@ it is required to remove any :cmd-option:`-include` switch that is passed to
642642
the compiler invocation, by having a dedicated scenario variable for a coverage
643643
build for instance.
644644

645+
To support annotations such as :ref:`exemptions<exemptions>` or :ref:`buffer
646+
output indications<manual_dump>`, the |gcvins| attempts to preserve comments
647+
when preprocessing the sources. If this is not possible (e.g. due to illegal
648+
concatenation of a comment with another token), the tool will emit a warning
649+
and ignore any in-source annotation for the mentioned file, as well as any
650+
other transitively included file.
651+
645652
Function and call coverage limitations
646653
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
647654

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#define CONCAT(X, Y) X##Y
2+
3+
inline int
4+
ident (int x)
5+
{
6+
/* GNATCOV_EXEMPT_ON unused*/
7+
return 0; // # noeval
8+
/*GNATCOV_EXEMPT_OFF */
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include "pkg.h"
2+
3+
int
4+
main ()
5+
{
6+
int CONCAT (/*empty*/, my_var) = 0; // # st
7+
return CONCAT (/*something else*/, my_var); // # st
8+
}
9+
10+
//# test_pkg.c
11+
//
12+
// /st/ l+ ## 0
13+
14+
//# pkg.h
15+
//
16+
// /noeval/ l- ## s-
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bin-traces DEAD Check instrumentation-specific behavior
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Test that gnatcov does not crash when instrumenting a source that cannot be
3+
preprocessed while preserving comments, and instead emits a warning stating
4+
that annotations are ignored.
5+
"""
6+
7+
import os
8+
9+
from SCOV.tc import TestCase
10+
from SCOV.tctl import CAT
11+
from SUITE.context import thistest
12+
from SUITE.cutils import contents_of
13+
14+
wd = "s_pkg"
15+
16+
warning_pat = (
17+
r"warning: Could not preserve comments while pre-processing .*test_pkg\.c"
18+
r", annotations in comments within this file or included headers will not"
19+
r" be taken into account"
20+
)
21+
22+
TestCase(
23+
category=CAT.stmt,
24+
tolerate_messages=warning_pat,
25+
).run()
26+
27+
# Actually check that the warning got emitted
28+
thistest.fail_if_no_match(
29+
what="missing warning in the output of 'gnatcov instrument'",
30+
regexp=warning_pat,
31+
actual=contents_of(os.path.join(wd, "xinstr.out")),
32+
)
33+
34+
thistest.result()

tools/gnatcov/instrument-c.adb

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3019,8 +3019,11 @@ package body Instrument.C is
30193019
PP_Filename : out Unbounded_String;
30203020
Options : in out Analysis_Options)
30213021
is
3022+
Base_Cmd : Command_Type;
3023+
-- The command to preprocess the file that we save
3024+
30223025
Cmd : Command_Type;
3023-
-- The command to preprocess the file
3026+
-- The actual command to preprocess the file
30243027

30253028
Success : Boolean;
30263029
-- Whether this command is successful
@@ -3050,38 +3053,42 @@ package body Instrument.C is
30503053
return;
30513054
end if;
30523055

3053-
Cmd :=
3056+
Base_Cmd :=
30543057
(Command => Prj.Compiler_Driver (Instrumenter.Language),
30553058
others => <>);
30563059

30573060
-- Add the preprocessing flag
30583061

3059-
Append_Arg (Cmd, "-E");
3060-
3061-
-- Keep the code comments as they may contain exemption / coverage
3062-
-- disabling markers.
3063-
3064-
Append_Arg (Cmd, "-C");
3062+
Append_Arg (Base_Cmd, "-E");
30653063

30663064
-- Add all of the compiler / compiler driver options to the
30673065
-- preprocessing command line.
30683066

3069-
Append_Args (Cmd, Options.Raw_Switches);
3067+
Append_Args (Base_Cmd, Options.Raw_Switches);
30703068

3071-
Append_Arg (Cmd, Filename);
3069+
Append_Arg (Base_Cmd, Filename);
30723070

30733071
-- Register the preprocessing command. We need it to preprocess the file
30743072
-- when producing the report, and getting the text of macro expansions.
30753073
-- We don't need the options added afterwards, as they are just there
30763074
-- for the instrumentation process (and we do not want to pass a -o
30773075
-- option, as it would make paths too opaque at gnatcov coverage time).
30783076

3077+
-- Keep the code comments as they may contain exemption / coverage
3078+
-- disabling markers. This argument needs to be kept last in Base_Cmd as
3079+
-- we may need to remove it later if preprocessing with comments
3080+
-- preserved fails.
3081+
3082+
Append_Arg (Base_Cmd, "-C");
3083+
30793084
PP_Cmds.Insert
30803085
(Get_Index_From_Generic_Name
30813086
(Filename,
30823087
Kind => Files_Table.Source_File,
30833088
Indexed_Simple_Name => True),
3084-
Cmd);
3089+
Base_Cmd);
3090+
3091+
Cmd := Base_Cmd;
30853092

30863093
-- To get the include paths, we use the verbose output of cpp -E
30873094

@@ -3098,6 +3105,60 @@ package body Instrument.C is
30983105
Output_File => Preprocessor_Output_Filename,
30993106
Ignore_Error => True);
31003107

3108+
if not Success then
3109+
3110+
-- If it did not succeed, it might be due to comment preservation
3111+
-- (-C), which can result in invalid tokens being generated by
3112+
-- token-manipulating macros. E.G:
3113+
--
3114+
-- #define FOO (X, Y) X ## Y
3115+
--
3116+
-- int FOO(/*my*/, integer);
3117+
--
3118+
-- Without preserving comments the above declaration expands to int
3119+
-- integer;
3120+
--
3121+
-- But preserving comments makes the preprocessor error out as a
3122+
-- comment token is concatenated to something else, which is not
3123+
-- allowed.
3124+
--
3125+
-- In that case, retry preprocessing without preserving comment, but
3126+
-- emit a warning as we'll loose any annotations in the preprocessed
3127+
-- files or included headers.
3128+
3129+
Base_Cmd.Arguments.Delete_Last;
3130+
3131+
PP_Cmds.Replace
3132+
(Get_Index_From_Generic_Name
3133+
(Filename,
3134+
Kind => Files_Table.Source_File,
3135+
Indexed_Simple_Name => True),
3136+
Base_Cmd);
3137+
3138+
Cmd := Base_Cmd;
3139+
3140+
Append_Arg (Cmd, "-v");
3141+
Append_Arg (Cmd, "-o");
3142+
Append_Arg (Cmd, Preprocessed_Filename);
3143+
3144+
Success :=
3145+
Run_Command
3146+
(Command => Cmd,
3147+
Origin_Command_Name => "Preprocessing",
3148+
Output_File => Preprocessor_Output_Filename,
3149+
Ignore_Error => True);
3150+
3151+
-- If this preprocessing command succeeded, warn the user that we
3152+
-- will not be able to process in-source annotations for this file
3153+
-- and included headers.
3154+
3155+
if Success then
3156+
Warn
3157+
("Could not preserve comments while pre-processing " & Filename
3158+
& ", annotations in comments within this file or included"
3159+
& " headers will not be taken into account");
3160+
end if;
3161+
end if;
31013162
-- Clear the search path so that we populate it from the include search
31023163
-- paths in the logs.
31033164

0 commit comments

Comments
 (0)