@@ -93,13 +93,12 @@ static auto AddIdentifierName(Context& context, llvm::StringRef name)
93
93
94
94
// Adds the given source location and an `ImportIRInst` referring to it in
95
95
// `ImportIRId::Cpp`.
96
- static auto AddImportIRInst (Context& context ,
96
+ static auto AddImportIRInst (SemIR::File& file ,
97
97
clang::SourceLocation clang_source_loc)
98
98
-> SemIR::ImportIRInstId {
99
99
SemIR::ClangSourceLocId clang_source_loc_id =
100
- context.sem_ir ().clang_source_locs ().Add (clang_source_loc);
101
- return context.import_ir_insts ().Add (
102
- SemIR::ImportIRInst (clang_source_loc_id));
100
+ file.clang_source_locs ().Add (clang_source_loc);
101
+ return file.import_ir_insts ().Add (SemIR::ImportIRInst (clang_source_loc_id));
103
102
}
104
103
105
104
namespace {
@@ -116,15 +115,22 @@ namespace {
116
115
// wrong C++ diagnostics, and at the end of the Carbon program.
117
116
class CarbonClangDiagnosticConsumer : public clang ::DiagnosticConsumer {
118
117
public:
119
- // Creates an instance with the location that triggers calling Clang.
120
- // `context` must not be null.
118
+ // Creates an instance with the location that triggers calling Clang. The
119
+ // `context` is not stored here, and the diagnostics consumer is expected to
120
+ // outlive it.
121
121
explicit CarbonClangDiagnosticConsumer (
122
- Context* context, std::shared_ptr<clang::CompilerInvocation> invocation)
123
- : context_(context), invocation_(std::move(invocation)) {
124
- context->emitter ().AddFlushFn ([this ] { EmitDiagnostics (); });
122
+ Context& context, std::shared_ptr<clang::CompilerInvocation> invocation)
123
+ : sem_ir_(&context.sem_ir()),
124
+ emitter_(&context.emitter()),
125
+ invocation_(std::move(invocation)) {
126
+ emitter_->AddFlushFn ([this ] { EmitDiagnostics (); });
125
127
}
126
128
127
129
~CarbonClangDiagnosticConsumer () override {
130
+ // Do not inspect `emitter_` here; it's typically destroyed before the
131
+ // consumer is.
132
+ // TODO: If Clang produces diagnostics after check finishes, they'll get
133
+ // added to the list of pending diagnostics and never emitted.
128
134
CARBON_CHECK (diagnostic_infos_.empty (),
129
135
" Missing flush before destroying diagnostic consumer" );
130
136
}
@@ -136,7 +142,7 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
136
142
DiagnosticConsumer::HandleDiagnostic (diag_level, info);
137
143
138
144
SemIR::ImportIRInstId clang_import_ir_inst_id =
139
- AddImportIRInst (*context_ , info.getLocation ());
145
+ AddImportIRInst (*sem_ir_ , info.getLocation ());
140
146
141
147
llvm::SmallString<256 > message;
142
148
info.FormatDiagnostic (message);
@@ -163,57 +169,57 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
163
169
.snippet = snippet_stream.TakeStr ()});
164
170
}
165
171
172
+ // Returns the diagnostic to use for a given Clang diagnostic level.
173
+ static auto GetDiagnostic (clang::DiagnosticsEngine::Level level)
174
+ -> const Diagnostics::DiagnosticBase<std::string>& {
175
+ switch (level) {
176
+ case clang::DiagnosticsEngine::Ignored: {
177
+ CARBON_FATAL (" Emitting an ignored diagnostic" );
178
+ break ;
179
+ }
180
+ case clang::DiagnosticsEngine::Note: {
181
+ CARBON_DIAGNOSTIC (CppInteropParseNote, Note, " {0}" , std::string);
182
+ return CppInteropParseNote;
183
+ }
184
+ case clang::DiagnosticsEngine::Remark:
185
+ case clang::DiagnosticsEngine::Warning: {
186
+ // TODO: Add a distinct Remark level to Carbon diagnostics, and stop
187
+ // mapping remarks to warnings.
188
+ CARBON_DIAGNOSTIC (CppInteropParseWarning, Warning, " {0}" , std::string);
189
+ return CppInteropParseWarning;
190
+ }
191
+ case clang::DiagnosticsEngine::Error:
192
+ case clang::DiagnosticsEngine::Fatal: {
193
+ CARBON_DIAGNOSTIC (CppInteropParseError, Error, " {0}" , std::string);
194
+ return CppInteropParseError;
195
+ }
196
+ }
197
+ }
198
+
166
199
// Outputs Carbon diagnostics based on the collected Clang diagnostics. Must
167
200
// be called after the AST is set in the context.
168
201
auto EmitDiagnostics () -> void {
169
- CARBON_CHECK (context_-> sem_ir (). cpp_ast (),
202
+ CARBON_CHECK (sem_ir_-> cpp_ast (),
170
203
" Attempted to emit diagnostics before the AST Unit is loaded" );
171
204
172
205
for (size_t i = 0 ; i != diagnostic_infos_.size (); ++i) {
173
206
const ClangDiagnosticInfo& info = diagnostic_infos_[i];
174
- switch (info.level ) {
175
- case clang::DiagnosticsEngine::Ignored:
176
- case clang::DiagnosticsEngine::Note:
177
- case clang::DiagnosticsEngine::Remark: {
178
- context_->TODO (
179
- SemIR::LocId (info.import_ir_inst_id ),
180
- llvm::formatv (
181
- " Unsupported: C++ diagnostic level for diagnostic\n {0}" ,
182
- info.message ));
183
- break ;
184
- }
185
- case clang::DiagnosticsEngine::Warning:
186
- case clang::DiagnosticsEngine::Error:
187
- case clang::DiagnosticsEngine::Fatal: {
188
- CARBON_DIAGNOSTIC (CppInteropParseWarning, Warning, " {0}" ,
189
- std::string);
190
- CARBON_DIAGNOSTIC (CppInteropParseError, Error, " {0}" , std::string);
191
- auto builder = context_->emitter ().Build (
192
- SemIR::LocId (info.import_ir_inst_id ),
193
- info.level == clang::DiagnosticsEngine::Warning
194
- ? CppInteropParseWarning
195
- : CppInteropParseError,
196
- info.message );
197
- builder.OverrideSnippet (info.snippet );
198
- for (;
199
- i + 1 < diagnostic_infos_.size () &&
200
- diagnostic_infos_[i + 1 ].level == clang::DiagnosticsEngine::Note;
201
- ++i) {
202
- const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1 ];
203
- CARBON_DIAGNOSTIC (CppInteropParseNote, Note, " {0}" , std::string);
204
- builder
205
- .Note (SemIR::LocId (note_info.import_ir_inst_id ),
206
- CppInteropParseNote, note_info.message )
207
- .OverrideSnippet (note_info.snippet );
208
- }
209
- // TODO: This will apply all current Carbon annotation functions. We
210
- // should instead track how Clang's context notes and Carbon's
211
- // annotation functions are interleaved, and interleave the notes in
212
- // the same order.
213
- builder.Emit ();
214
- break ;
215
- }
207
+ auto builder = emitter_->Build (SemIR::LocId (info.import_ir_inst_id ),
208
+ GetDiagnostic (info.level ), info.message );
209
+ builder.OverrideSnippet (info.snippet );
210
+ for (; i + 1 < diagnostic_infos_.size () &&
211
+ diagnostic_infos_[i + 1 ].level == clang::DiagnosticsEngine::Note;
212
+ ++i) {
213
+ const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1 ];
214
+ builder
215
+ .Note (SemIR::LocId (note_info.import_ir_inst_id ),
216
+ GetDiagnostic (note_info.level ), note_info.message )
217
+ .OverrideSnippet (note_info.snippet );
216
218
}
219
+ // TODO: This will apply all current Carbon annotation functions. We
220
+ // should instead track how Clang's context notes and Carbon's annotation
221
+ // functions are interleaved, and interleave the notes in the same order.
222
+ builder.Emit ();
217
223
}
218
224
diagnostic_infos_.clear ();
219
225
}
@@ -267,8 +273,11 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
267
273
std::string snippet;
268
274
};
269
275
270
- // The type-checking context in which we're running Clang.
271
- Context* context_;
276
+ // The Carbon file that this C++ compilation is attached to.
277
+ SemIR::File* sem_ir_;
278
+
279
+ // The diagnostic emitter that we're emitting diagnostics into.
280
+ DiagnosticEmitterBase* emitter_;
272
281
273
282
// The compiler invocation that is producing the diagnostics.
274
283
std::shared_ptr<clang::CompilerInvocation> invocation_;
@@ -316,7 +325,7 @@ static auto GenerateAst(
316
325
llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags (
317
326
clang::CompilerInstance::createDiagnostics (
318
327
*fs, invocation->getDiagnosticOpts (),
319
- new CarbonClangDiagnosticConsumer (& context, invocation),
328
+ new CarbonClangDiagnosticConsumer (context, invocation),
320
329
/* ShouldOwnClient=*/ true ));
321
330
322
331
// Extract the input from the frontend invocation and make sure it makes
@@ -587,7 +596,8 @@ static auto BuildClassDecl(Context& context,
587
596
static auto ImportCXXRecordDecl (Context& context,
588
597
clang::CXXRecordDecl* clang_decl)
589
598
-> SemIR::InstId {
590
- auto import_ir_inst_id = AddImportIRInst (context, clang_decl->getLocation ());
599
+ auto import_ir_inst_id =
600
+ AddImportIRInst (context.sem_ir (), clang_decl->getLocation ());
591
601
592
602
auto [class_id, class_inst_id] = BuildClassDecl (
593
603
context, import_ir_inst_id, GetParentNameScopeId (context, clang_decl),
0 commit comments