clang_generator: Turn fatal error on struc-by-value into warning

An `absl::StatusCode` of `kCancelled` now indicates warnings inside the emitter.

PiperOrigin-RevId: 485851898
Change-Id: I10a57cbc1b6c2d4b708c3c19aa0fa71451845a22
This commit is contained in:
Christian Blichmann 2022-11-03 06:01:50 -07:00 committed by Copybara-Service
parent 3abfefaf3b
commit ce26b55e26
5 changed files with 64 additions and 20 deletions

View File

@ -14,7 +14,9 @@
#include "sandboxed_api/tools/clang_generator/diagnostics.h" #include "sandboxed_api/tools/clang_generator/diagnostics.h"
#include "absl/status/status.h"
#include "absl/strings/cord.h" #include "absl/strings/cord.h"
#include "clang/Basic/Diagnostic.h"
namespace sapi { namespace sapi {
@ -22,8 +24,9 @@ constexpr absl::string_view kSapiStatusPayload =
"https://github.com/google/sandboxed-api"; "https://github.com/google/sandboxed-api";
absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc, absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
absl::StatusCode code,
absl::string_view message) { absl::string_view message) {
absl::Status status = absl::UnknownError(message); absl::Status status(code, message);
absl::Cord payload; absl::Cord payload;
uint64_t raw_loc = loc.getRawEncoding(); uint64_t raw_loc = loc.getRawEncoding();
payload.Append( payload.Append(
@ -32,6 +35,11 @@ absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
return status; return status;
} }
absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
absl::string_view message) {
return MakeStatusWithDiagnostic(loc, absl::StatusCode::kUnknown, message);
}
absl::optional<clang::SourceLocation> GetDiagnosticLocationFromStatus( absl::optional<clang::SourceLocation> GetDiagnosticLocationFromStatus(
const absl::Status& status) { const absl::Status& status) {
if (auto payload = if (auto payload =
@ -43,14 +51,31 @@ absl::optional<clang::SourceLocation> GetDiagnosticLocationFromStatus(
return absl::nullopt; return absl::nullopt;
} }
clang::DiagnosticBuilder ReportFatalError(clang::DiagnosticsEngine& de, namespace {
clang::SourceLocation loc,
absl::string_view message) { clang::DiagnosticBuilder GetDiagnosticBuilder(
clang::DiagnosticsEngine& de, clang::SourceLocation loc,
clang::DiagnosticsEngine::Level level, absl::string_view message) {
clang::DiagnosticBuilder builder = clang::DiagnosticBuilder builder =
de.Report(loc, de.getCustomDiagID(clang::DiagnosticsEngine::Fatal, de.Report(loc, de.getCustomDiagID(level, "header generation: %0"));
"header generation failed: %0"));
builder.AddString(llvm::StringRef(message.data(), message.size())); builder.AddString(llvm::StringRef(message.data(), message.size()));
return builder; return builder;
} }
} // namespace
clang::DiagnosticBuilder ReportFatalError(clang::DiagnosticsEngine& de,
clang::SourceLocation loc,
absl::string_view message) {
return GetDiagnosticBuilder(de, loc, clang::DiagnosticsEngine::Fatal,
message);
}
clang::DiagnosticBuilder ReportWarning(clang::DiagnosticsEngine& de,
clang::SourceLocation loc,
absl::string_view message) {
return GetDiagnosticBuilder(de, loc, clang::DiagnosticsEngine::Warning,
message);
}
} // namespace sapi } // namespace sapi

View File

@ -23,6 +23,12 @@
namespace sapi { namespace sapi {
// Returns a new status with a payload that encodes the specified Clang source
// location.
absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
absl::StatusCode code,
absl::string_view message);
// Returns a new UNKNOWN status with a payload that encodes the specified Clang // Returns a new UNKNOWN status with a payload that encodes the specified Clang
// source location. // source location.
absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc, absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
@ -32,6 +38,10 @@ absl::Status MakeStatusWithDiagnostic(clang::SourceLocation loc,
absl::optional<clang::SourceLocation> GetDiagnosticLocationFromStatus( absl::optional<clang::SourceLocation> GetDiagnosticLocationFromStatus(
const absl::Status& status); const absl::Status& status);
clang::DiagnosticBuilder ReportWarning(clang::DiagnosticsEngine& de,
clang::SourceLocation loc,
absl::string_view message);
clang::DiagnosticBuilder ReportFatalError(clang::DiagnosticsEngine& de, clang::DiagnosticBuilder ReportFatalError(clang::DiagnosticsEngine& de,
clang::SourceLocation loc, clang::SourceLocation loc,
absl::string_view message); absl::string_view message);

View File

@ -298,8 +298,9 @@ absl::StatusOr<std::string> EmitFunction(const clang::FunctionDecl* decl) {
auto function_name = ToStringView(decl->getName()); auto function_name = ToStringView(decl->getName());
const clang::QualType return_type = decl->getDeclaredReturnType(); const clang::QualType return_type = decl->getDeclaredReturnType();
if (return_type->isRecordType()) { if (return_type->isRecordType()) {
return MakeStatusWithDiagnostic(decl->getBeginLoc(), return MakeStatusWithDiagnostic(
"returning record by value"); decl->getBeginLoc(), absl::StatusCode::kCancelled,
"returning record by value, skipping function");
} }
const bool returns_void = return_type->isVoidType(); const bool returns_void = return_type->isVoidType();
@ -320,9 +321,10 @@ absl::StatusOr<std::string> EmitFunction(const clang::FunctionDecl* decl) {
const clang::ParmVarDecl* param = decl->getParamDecl(i); const clang::ParmVarDecl* param = decl->getParamDecl(i);
if (param->getType()->isRecordType()) { if (param->getType()->isRecordType()) {
return MakeStatusWithDiagnostic( return MakeStatusWithDiagnostic(
param->getBeginLoc(), param->getBeginLoc(), absl::StatusCode::kCancelled,
absl::StrCat("passing record parameter '", absl::StrCat("passing record parameter '",
ToStringView(param->getName()), "' by value")); ToStringView(param->getName()),
"' by value, skipping function"));
} }
ParameterInfo& param_info = params.emplace_back(); ParameterInfo& param_info = params.emplace_back();

View File

@ -165,34 +165,37 @@ TEST_F(EmitterTest, RemoveQualifiers) {
ElementsAre("struct A { int data; }")); ElementsAre("struct A { int data; }"));
} }
TEST_F(EmitterTest, StructByValueFails) { TEST_F(EmitterTest, StructByValueSkipsFunction) {
EmitterForTesting emitter; EmitterForTesting emitter;
EXPECT_THAT( EXPECT_THAT(
RunFrontendAction( RunFrontendAction(
R"(struct A { int data; }; R"(struct A { int data; };
extern "C" int Structize(A a);)", extern "C" int Structize(A a);)",
std::make_unique<GeneratorAction>(emitter, GeneratorOptions())), std::make_unique<GeneratorAction>(emitter, GeneratorOptions())),
Not(IsOk())); IsOk());
EXPECT_THAT(emitter.functions_, IsEmpty());
} }
TEST_F(EmitterTest, ReturnStructByValueFails) { TEST_F(EmitterTest, ReturnStructByValueSkipsFunction) {
EmitterForTesting emitter; EmitterForTesting emitter;
EXPECT_THAT( EXPECT_THAT(
RunFrontendAction( RunFrontendAction(
R"(struct A { int data; }; R"(struct A { int data; };
extern "C" A Structize();)", extern "C" A Structize();)",
std::make_unique<GeneratorAction>(emitter, GeneratorOptions())), std::make_unique<GeneratorAction>(emitter, GeneratorOptions())),
Not(IsOk())); IsOk());
EXPECT_THAT(emitter.functions_, IsEmpty());
} }
TEST_F(EmitterTest, TypedefStructByValueFails) { TEST_F(EmitterTest, TypedefStructByValueSkipsFunction) {
EmitterForTesting emitter; EmitterForTesting emitter;
EXPECT_THAT( EXPECT_THAT(
RunFrontendAction( RunFrontendAction(
R"(typedef struct { int data; } A; R"(typedef struct { int data; } A;
extern "C" int Structize(A a);)", extern "C" int Structize(A a);)",
std::make_unique<GeneratorAction>(emitter, GeneratorOptions())), std::make_unique<GeneratorAction>(emitter, GeneratorOptions())),
Not(IsOk())); IsOk());
EXPECT_THAT(emitter.functions_, IsEmpty());
} }
TEST(IncludeGuard, CreatesRandomizedGuardForEmptyFilename) { TEST(IncludeGuard, CreatesRandomizedGuardForEmptyFilename) {

View File

@ -78,6 +78,7 @@ void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
ReportFatalError(context.getDiagnostics(), ReportFatalError(context.getDiagnostics(),
context.getTranslationUnitDecl()->getBeginLoc(), context.getTranslationUnitDecl()->getBeginLoc(),
"AST traversal exited early"); "AST traversal exited early");
return;
} }
emitter_.AddTypesFiltered(visitor_.collector_.collected()); emitter_.AddTypesFiltered(visitor_.collector_.collected());
@ -85,10 +86,13 @@ void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
for (clang::FunctionDecl* func : visitor_.functions_) { for (clang::FunctionDecl* func : visitor_.functions_) {
absl::Status status = emitter_.AddFunction(func); absl::Status status = emitter_.AddFunction(func);
if (!status.ok()) { if (!status.ok()) {
ReportFatalError( clang::SourceLocation loc =
context.getDiagnostics(), GetDiagnosticLocationFromStatus(status).value_or(func->getBeginLoc());
GetDiagnosticLocationFromStatus(status).value_or(func->getBeginLoc()), if (absl::IsCancelled(status)) {
status.message()); ReportWarning(context.getDiagnostics(), loc, status.message());
continue;
}
ReportFatalError(context.getDiagnostics(), loc, status.message());
break; break;
} }
} }