Skip to content

Commit d6670af

Browse files
Merge pull request #365 from correctcomputation/root-cause-test-line-numbers
Convert root_cause test to use Clang's built-in diagnostic verifier.
2 parents 679d3b5 + cf652f5 commit d6670af

File tree

5 files changed

+87
-45
lines changed

5 files changed

+87
-45
lines changed

clang/include/clang/3C/3C.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ struct _3COptions {
6565
bool RemoveItypes;
6666
bool ForceItypes;
6767
#endif
68+
69+
// Currently applies only to the rewriting phase (because it is the only phase
70+
// that generates diagnostics, except for the declaration merging diagnostics
71+
// that are currently fatal) and uses the default "expected" prefix.
72+
bool VerifyDiagnosticOutput;
6873
};
6974

7075
// The main interface exposed by the 3C to interact with the tool.

clang/lib/3C/3C.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ bool DisableCCTypeChecker;
5454
bool WarnRootCause;
5555
bool WarnAllRootCause;
5656
std::set<std::string> FilePaths;
57+
bool VerifyDiagnosticOutput;
5758

5859
#ifdef FIVE_C
5960
bool RemoveItypes;
@@ -95,19 +96,39 @@ class RewriteAction : public ASTFrontendAction {
9596

9697
template <typename T>
9798
std::unique_ptr<FrontendActionFactory>
98-
newFrontendActionFactoryA(ProgramInfo &I) {
99+
newFrontendActionFactoryA(ProgramInfo &I, bool VerifyTheseDiagnostics = false) {
99100
class ArgFrontendActionFactory : public FrontendActionFactory {
100101
public:
101-
explicit ArgFrontendActionFactory(ProgramInfo &I) : Info(I) {}
102+
explicit ArgFrontendActionFactory(ProgramInfo &I,
103+
bool VerifyTheseDiagnostics)
104+
: Info(I), VerifyTheseDiagnostics(VerifyTheseDiagnostics) {}
102105

103106
FrontendAction *create() override { return new T(Info); }
104107

108+
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
109+
FileManager *Files,
110+
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
111+
DiagnosticConsumer *DiagConsumer) override {
112+
if (VerifyTheseDiagnostics) {
113+
// Mirroring the logic of clang::ParseDiagnosticArgs in
114+
// clang/lib/Frontend/CompilerInvocation.cpp. In particular, note that
115+
// VerifyPrefixes is assumed to be sorted, in case we add more in the
116+
// future.
117+
DiagnosticOptions &DiagOpts = Invocation->getDiagnosticOpts();
118+
DiagOpts.VerifyDiagnostics = true;
119+
DiagOpts.VerifyPrefixes.push_back("expected");
120+
}
121+
return FrontendActionFactory::runInvocation(
122+
Invocation, Files, PCHContainerOps, DiagConsumer);
123+
}
124+
105125
private:
106126
ProgramInfo &Info;
127+
bool VerifyTheseDiagnostics;
107128
};
108129

109130
return std::unique_ptr<FrontendActionFactory>(
110-
new ArgFrontendActionFactory(I));
131+
new ArgFrontendActionFactory(I, VerifyTheseDiagnostics));
111132
}
112133

113134
ArgumentsAdjuster getIgnoreCheckedPointerAdjuster() {
@@ -192,6 +213,7 @@ _3CInterface::_3CInterface(const struct _3COptions &CCopt,
192213
AllocatorFunctions = CCopt.AllocatorFunctions;
193214
WarnRootCause = CCopt.WarnRootCause || CCopt.WarnAllRootCause;
194215
WarnAllRootCause = CCopt.WarnAllRootCause;
216+
VerifyDiagnosticOutput = CCopt.VerifyDiagnosticOutput;
195217

196218
#ifdef FIVE_C
197219
RemoveItypes = CCopt.RemoveItypes;
@@ -246,9 +268,11 @@ bool _3CInterface::buildInitialConstraints() {
246268
std::unique_ptr<ToolAction> ConstraintTool = newFrontendActionFactoryA<
247269
GenericAction<ConstraintBuilderConsumer, ProgramInfo>>(GlobalProgramInfo);
248270

249-
if (ConstraintTool)
250-
Tool.run(ConstraintTool.get());
251-
else
271+
if (ConstraintTool) {
272+
int ToolExitCode = Tool.run(ConstraintTool.get());
273+
if (ToolExitCode != 0)
274+
return false;
275+
} else
252276
llvm_unreachable("No action");
253277

254278
if (!GlobalProgramInfo.link()) {
@@ -297,9 +321,11 @@ bool _3CInterface::solveConstraints(bool ComputeInterimState) {
297321
std::unique_ptr<ToolAction> ABInfTool = newFrontendActionFactoryA<
298322
GenericAction<AllocBasedBoundsInference, ProgramInfo>>(
299323
GlobalProgramInfo);
300-
if (ABInfTool)
301-
Tool.run(ABInfTool.get());
302-
else
324+
if (ABInfTool) {
325+
int ToolExitCode = Tool.run(ABInfTool.get());
326+
if (ToolExitCode != 0)
327+
return false;
328+
} else
303329
llvm_unreachable("No Action");
304330

305331
// Propagate the information from allocator bounds.
@@ -310,9 +336,11 @@ bool _3CInterface::solveConstraints(bool ComputeInterimState) {
310336
// after constraint solving but before rewriting.
311337
std::unique_ptr<ToolAction> IMTool = newFrontendActionFactoryA<
312338
GenericAction<IntermediateToolHook, ProgramInfo>>(GlobalProgramInfo);
313-
if (IMTool)
314-
Tool.run(IMTool.get());
315-
else
339+
if (IMTool) {
340+
int ToolExitCode = Tool.run(IMTool.get());
341+
if (ToolExitCode != 0)
342+
return false;
343+
} else
316344
llvm_unreachable("No Action");
317345

318346
if (AllTypes) {
@@ -362,10 +390,13 @@ bool _3CInterface::writeConvertedFileToDisk(const std::string &FilePath) {
362390
Tool.appendArgumentsAdjuster(getIgnoreCheckedPointerAdjuster());
363391
std::unique_ptr<ToolAction> RewriteTool =
364392
newFrontendActionFactoryA<RewriteAction<RewriteConsumer, ProgramInfo>>(
365-
GlobalProgramInfo);
393+
GlobalProgramInfo, VerifyDiagnosticOutput);
366394

367-
if (RewriteTool)
368-
Tool.run(RewriteTool.get());
395+
if (RewriteTool) {
396+
int ToolExitCode = Tool.run(RewriteTool.get());
397+
if (ToolExitCode != 0)
398+
return false;
399+
}
369400
return true;
370401
}
371402
return false;
@@ -379,10 +410,12 @@ bool _3CInterface::writeAllConvertedFilesToDisk() {
379410
// Rewrite the input files
380411
std::unique_ptr<ToolAction> RewriteTool =
381412
newFrontendActionFactoryA<RewriteAction<RewriteConsumer, ProgramInfo>>(
382-
GlobalProgramInfo);
383-
if (RewriteTool)
384-
Tool.run(RewriteTool.get());
385-
else
413+
GlobalProgramInfo, VerifyDiagnosticOutput);
414+
if (RewriteTool) {
415+
int ToolExitCode = Tool.run(RewriteTool.get());
416+
if (ToolExitCode != 0)
417+
return false;
418+
} else
386419
llvm_unreachable("No action");
387420

388421
return true;

clang/test/3C/partial_checked_arr.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// RUN: 3c -addcr -alltypes %s | %clang -c -f3c-tool -fcheckedc-extension -x c -o %t1.unused -
33
// RUN: 3c -addcr %s | FileCheck -match-full-lines -check-prefixes="CHECK_NOALL","CHECK" %s
44
// RUN: 3c -addcr %s | %clang -c -f3c-tool -fcheckedc-extension -x c -o %t2.unused -
5-
// RUN: 3c -alltypes %s > %t
6-
// RUN: 3c -alltypes %t | count 0
5+
// RUN: 3c -alltypes -output-postfix=checked %s
6+
// RUN: 3c -alltypes %S/partial_checked_arr.checked.c -- | count 0
7+
// RUN: rm %S/partial_checked_arr.checked.c
78

89
int strcmp(const char *src1 : itype(_Nt_array_ptr<const char>),
910
const char *src2 : itype(_Nt_array_ptr<const char>));

clang/test/3C/root_cause.c

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,43 @@
1-
// RUN: 3c -extra-arg="-Wno-everything" -alltypes -warn-root-cause %s 2>&1 >%t.unused | FileCheck %s
1+
// RUN: 3c -extra-arg="-Wno-everything" -verify -alltypes -warn-root-cause %s
22

33
// This test is unusual in that it checks for the errors in the code
44

55
#include <stddef.h>
66
extern _Itype_for_any(T) void *malloc(size_t size) : itype(_Array_ptr<T>) byte_count(size);
77

8-
void *x;
9-
// CHECK-DAG: Default void* type
8+
void *x; // expected-warning {{Default void* type}}
109

1110
void test0() {
1211
int *a;
1312
char *b;
14-
a = b;
15-
// CHECK-DAG: Cast from int * to char *
13+
a = b; // expected-warning {{Cast from char * to int *}}
1614

1715
int *c;
18-
(char*) c;
19-
// CHECK-DAG: Cast from int * to char *
16+
(char*) c; // expected-warning {{Cast from int * to char *}}
2017

2118

2219
int *e;
2320
char *f;
24-
f = (char*) e;
25-
// CHECK-DAG: Cast from char * to int *
21+
f = (char*) e; // expected-warning {{Cast from int * to char *}}
2622
}
2723

2824
void test1() {
2925
int a;
3026
int *b;
31-
b = malloc(sizeof(int));
27+
b = malloc(sizeof(int)); // expected-warning {{Bad pointer type solution}}
3228
b[0] = 1;
3329

3430
union u {
35-
int *a;
36-
// CHECK-DAG: Union or external struct field encountered
37-
int *b;
38-
// CHECK-DAG: Union or external struct field encountered
31+
int *a; // expected-warning {{Union or external struct field encountered}}
32+
int *b; // expected-warning {{Union or external struct field encountered}}
3933
};
4034

4135
void (*c)(void);
42-
c++;
43-
// CHECK-DAG: Pointer arithmetic performed on a function pointer
36+
c++; // expected-warning {{Pointer arithmetic performed on a function pointer}}
4437

45-
int *d = malloc(1);
46-
// CHECK-DAG: Unsafe call to allocator function
38+
int *d = malloc(1); // expected-warning {{Unsafe call to allocator function}}
4739
}
4840

49-
extern int *glob;
50-
// CHECK-DAG: External global variable glob has no definition
41+
extern int *glob; // expected-warning {{External global variable glob has no definition}}
5142

52-
void (*f)(void *);
53-
// CHECK-DAG: Default void* type
54-
55-
// CHECK-DAG: 11 warnings generated.
43+
void (*f)(void *); // expected-warning {{Default void* type}}

clang/tools/3c/3CStandalone.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ static cl::opt<bool>
121121
"even those unlikely to be interesting."),
122122
cl::init(false), cl::cat(_3CCategory));
123123

124+
// https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details
125+
//
126+
// Analogous to the -verify option of `clang -cc1`, but currently applies only
127+
// to the rewriting phase (because it is the only phase that generates
128+
// diagnostics, except for the declaration merging diagnostics that are
129+
// currently fatal). No checking of diagnostics from the other phases is
130+
// performed. We cannot simply have the caller pass `-extra-arg=-Xclang
131+
// -extra-arg=-verify` because that would expect each phase to produce the same
132+
// set of diagnostics.
133+
static cl::opt<bool> OptVerifyDiagnosticOutput(
134+
"verify",
135+
cl::desc("Verify diagnostic output (for automated testing of 3C)."),
136+
cl::init(false), cl::cat(_3CCategory), cl::Hidden);
137+
124138
#ifdef FIVE_C
125139
static cl::opt<bool> OptRemoveItypes(
126140
"remove-itypes",
@@ -161,6 +175,7 @@ int main(int argc, const char **argv) {
161175
CcOptions.DisableCCTypeChecker = OptDiableCCTypeChecker;
162176
CcOptions.WarnRootCause = OptWarnRootCause;
163177
CcOptions.WarnAllRootCause = OptWarnAllRootCause;
178+
CcOptions.VerifyDiagnosticOutput = OptVerifyDiagnosticOutput;
164179

165180
#ifdef FIVE_C
166181
CcOptions.RemoveItypes = OptRemoveItypes;

0 commit comments

Comments
 (0)