File: | build/source/clang/include/clang/Basic/Diagnostic.h |
Warning: | line 1188, column 5 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- ParsePragma.cpp - Language specific pragma parsing ---------------===// | ||||
2 | // | ||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
6 | // | ||||
7 | //===----------------------------------------------------------------------===// | ||||
8 | // | ||||
9 | // This file implements the language specific #pragma handlers. | ||||
10 | // | ||||
11 | //===----------------------------------------------------------------------===// | ||||
12 | |||||
13 | #include "clang/AST/ASTContext.h" | ||||
14 | #include "clang/Basic/PragmaKinds.h" | ||||
15 | #include "clang/Basic/TargetInfo.h" | ||||
16 | #include "clang/Lex/Preprocessor.h" | ||||
17 | #include "clang/Lex/Token.h" | ||||
18 | #include "clang/Parse/LoopHint.h" | ||||
19 | #include "clang/Parse/ParseDiagnostic.h" | ||||
20 | #include "clang/Parse/Parser.h" | ||||
21 | #include "clang/Parse/RAIIObjectsForParser.h" | ||||
22 | #include "clang/Sema/EnterExpressionEvaluationContext.h" | ||||
23 | #include "clang/Sema/Scope.h" | ||||
24 | #include "llvm/ADT/ArrayRef.h" | ||||
25 | #include "llvm/ADT/StringSwitch.h" | ||||
26 | #include <optional> | ||||
27 | using namespace clang; | ||||
28 | |||||
29 | namespace { | ||||
30 | |||||
31 | struct PragmaAlignHandler : public PragmaHandler { | ||||
32 | explicit PragmaAlignHandler() : PragmaHandler("align") {} | ||||
33 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
34 | Token &FirstToken) override; | ||||
35 | }; | ||||
36 | |||||
37 | struct PragmaGCCVisibilityHandler : public PragmaHandler { | ||||
38 | explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {} | ||||
39 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
40 | Token &FirstToken) override; | ||||
41 | }; | ||||
42 | |||||
43 | struct PragmaOptionsHandler : public PragmaHandler { | ||||
44 | explicit PragmaOptionsHandler() : PragmaHandler("options") {} | ||||
45 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
46 | Token &FirstToken) override; | ||||
47 | }; | ||||
48 | |||||
49 | struct PragmaPackHandler : public PragmaHandler { | ||||
50 | explicit PragmaPackHandler() : PragmaHandler("pack") {} | ||||
51 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
52 | Token &FirstToken) override; | ||||
53 | }; | ||||
54 | |||||
55 | struct PragmaClangSectionHandler : public PragmaHandler { | ||||
56 | explicit PragmaClangSectionHandler(Sema &S) | ||||
57 | : PragmaHandler("section"), Actions(S) {} | ||||
58 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
59 | Token &FirstToken) override; | ||||
60 | |||||
61 | private: | ||||
62 | Sema &Actions; | ||||
63 | }; | ||||
64 | |||||
65 | struct PragmaMSStructHandler : public PragmaHandler { | ||||
66 | explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} | ||||
67 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
68 | Token &FirstToken) override; | ||||
69 | }; | ||||
70 | |||||
71 | struct PragmaUnusedHandler : public PragmaHandler { | ||||
72 | PragmaUnusedHandler() : PragmaHandler("unused") {} | ||||
73 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
74 | Token &FirstToken) override; | ||||
75 | }; | ||||
76 | |||||
77 | struct PragmaWeakHandler : public PragmaHandler { | ||||
78 | explicit PragmaWeakHandler() : PragmaHandler("weak") {} | ||||
79 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
80 | Token &FirstToken) override; | ||||
81 | }; | ||||
82 | |||||
83 | struct PragmaRedefineExtnameHandler : public PragmaHandler { | ||||
84 | explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {} | ||||
85 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
86 | Token &FirstToken) override; | ||||
87 | }; | ||||
88 | |||||
89 | struct PragmaOpenCLExtensionHandler : public PragmaHandler { | ||||
90 | PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {} | ||||
91 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
92 | Token &FirstToken) override; | ||||
93 | }; | ||||
94 | |||||
95 | |||||
96 | struct PragmaFPContractHandler : public PragmaHandler { | ||||
97 | PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {} | ||||
98 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
99 | Token &FirstToken) override; | ||||
100 | }; | ||||
101 | |||||
102 | // Pragma STDC implementations. | ||||
103 | |||||
104 | /// PragmaSTDC_FENV_ACCESSHandler - "\#pragma STDC FENV_ACCESS ...". | ||||
105 | struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { | ||||
106 | PragmaSTDC_FENV_ACCESSHandler() : PragmaHandler("FENV_ACCESS") {} | ||||
107 | |||||
108 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
109 | Token &Tok) override { | ||||
110 | Token PragmaName = Tok; | ||||
111 | if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { | ||||
112 | PP.Diag(Tok.getLocation(), diag::warn_pragma_fp_ignored) | ||||
113 | << PragmaName.getIdentifierInfo()->getName(); | ||||
114 | return; | ||||
115 | } | ||||
116 | tok::OnOffSwitch OOS; | ||||
117 | if (PP.LexOnOffSwitch(OOS)) | ||||
118 | return; | ||||
119 | |||||
120 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
121 | 1); | ||||
122 | Toks[0].startToken(); | ||||
123 | Toks[0].setKind(tok::annot_pragma_fenv_access); | ||||
124 | Toks[0].setLocation(Tok.getLocation()); | ||||
125 | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | ||||
126 | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | ||||
127 | static_cast<uintptr_t>(OOS))); | ||||
128 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
129 | /*IsReinject=*/false); | ||||
130 | } | ||||
131 | }; | ||||
132 | |||||
133 | /// PragmaSTDC_CX_LIMITED_RANGEHandler - "\#pragma STDC CX_LIMITED_RANGE ...". | ||||
134 | struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { | ||||
135 | PragmaSTDC_CX_LIMITED_RANGEHandler() : PragmaHandler("CX_LIMITED_RANGE") {} | ||||
136 | |||||
137 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
138 | Token &Tok) override { | ||||
139 | tok::OnOffSwitch OOS; | ||||
140 | PP.LexOnOffSwitch(OOS); | ||||
141 | } | ||||
142 | }; | ||||
143 | |||||
144 | /// Handler for "\#pragma STDC FENV_ROUND ...". | ||||
145 | struct PragmaSTDC_FENV_ROUNDHandler : public PragmaHandler { | ||||
146 | PragmaSTDC_FENV_ROUNDHandler() : PragmaHandler("FENV_ROUND") {} | ||||
147 | |||||
148 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
149 | Token &Tok) override; | ||||
150 | }; | ||||
151 | |||||
152 | /// PragmaSTDC_UnknownHandler - "\#pragma STDC ...". | ||||
153 | struct PragmaSTDC_UnknownHandler : public PragmaHandler { | ||||
154 | PragmaSTDC_UnknownHandler() = default; | ||||
155 | |||||
156 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
157 | Token &UnknownTok) override { | ||||
158 | // C99 6.10.6p2, unknown forms are not allowed. | ||||
159 | PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored); | ||||
160 | } | ||||
161 | }; | ||||
162 | |||||
163 | struct PragmaFPHandler : public PragmaHandler { | ||||
164 | PragmaFPHandler() : PragmaHandler("fp") {} | ||||
165 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
166 | Token &FirstToken) override; | ||||
167 | }; | ||||
168 | |||||
169 | struct PragmaNoOpenMPHandler : public PragmaHandler { | ||||
170 | PragmaNoOpenMPHandler() : PragmaHandler("omp") { } | ||||
171 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
172 | Token &FirstToken) override; | ||||
173 | }; | ||||
174 | |||||
175 | struct PragmaOpenMPHandler : public PragmaHandler { | ||||
176 | PragmaOpenMPHandler() : PragmaHandler("omp") { } | ||||
177 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
178 | Token &FirstToken) override; | ||||
179 | }; | ||||
180 | |||||
181 | /// PragmaCommentHandler - "\#pragma comment ...". | ||||
182 | struct PragmaCommentHandler : public PragmaHandler { | ||||
183 | PragmaCommentHandler(Sema &Actions) | ||||
184 | : PragmaHandler("comment"), Actions(Actions) {} | ||||
185 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
186 | Token &FirstToken) override; | ||||
187 | |||||
188 | private: | ||||
189 | Sema &Actions; | ||||
190 | }; | ||||
191 | |||||
192 | struct PragmaDetectMismatchHandler : public PragmaHandler { | ||||
193 | PragmaDetectMismatchHandler(Sema &Actions) | ||||
194 | : PragmaHandler("detect_mismatch"), Actions(Actions) {} | ||||
195 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
196 | Token &FirstToken) override; | ||||
197 | |||||
198 | private: | ||||
199 | Sema &Actions; | ||||
200 | }; | ||||
201 | |||||
202 | struct PragmaFloatControlHandler : public PragmaHandler { | ||||
203 | PragmaFloatControlHandler(Sema &Actions) | ||||
204 | : PragmaHandler("float_control") {} | ||||
205 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
206 | Token &FirstToken) override; | ||||
207 | }; | ||||
208 | |||||
209 | struct PragmaMSPointersToMembers : public PragmaHandler { | ||||
210 | explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {} | ||||
211 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
212 | Token &FirstToken) override; | ||||
213 | }; | ||||
214 | |||||
215 | struct PragmaMSVtorDisp : public PragmaHandler { | ||||
216 | explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {} | ||||
217 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
218 | Token &FirstToken) override; | ||||
219 | }; | ||||
220 | |||||
221 | struct PragmaMSPragma : public PragmaHandler { | ||||
222 | explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} | ||||
223 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
224 | Token &FirstToken) override; | ||||
225 | }; | ||||
226 | |||||
227 | /// PragmaOptimizeHandler - "\#pragma clang optimize on/off". | ||||
228 | struct PragmaOptimizeHandler : public PragmaHandler { | ||||
229 | PragmaOptimizeHandler(Sema &S) | ||||
230 | : PragmaHandler("optimize"), Actions(S) {} | ||||
231 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
232 | Token &FirstToken) override; | ||||
233 | |||||
234 | private: | ||||
235 | Sema &Actions; | ||||
236 | }; | ||||
237 | |||||
238 | struct PragmaLoopHintHandler : public PragmaHandler { | ||||
239 | PragmaLoopHintHandler() : PragmaHandler("loop") {} | ||||
240 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
241 | Token &FirstToken) override; | ||||
242 | }; | ||||
243 | |||||
244 | struct PragmaUnrollHintHandler : public PragmaHandler { | ||||
245 | PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {} | ||||
246 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
247 | Token &FirstToken) override; | ||||
248 | }; | ||||
249 | |||||
250 | struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler { | ||||
251 | PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {} | ||||
252 | }; | ||||
253 | |||||
254 | struct PragmaMSIntrinsicHandler : public PragmaHandler { | ||||
255 | PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {} | ||||
256 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
257 | Token &FirstToken) override; | ||||
258 | }; | ||||
259 | |||||
260 | // "\#pragma fenv_access (on)". | ||||
261 | struct PragmaMSFenvAccessHandler : public PragmaHandler { | ||||
262 | PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {} | ||||
263 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
264 | Token &FirstToken) override { | ||||
265 | StringRef PragmaName = FirstToken.getIdentifierInfo()->getName(); | ||||
266 | if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { | ||||
267 | PP.Diag(FirstToken.getLocation(), diag::warn_pragma_fp_ignored) | ||||
268 | << PragmaName; | ||||
269 | return; | ||||
270 | } | ||||
271 | |||||
272 | Token Tok; | ||||
273 | PP.Lex(Tok); | ||||
274 | if (Tok.isNot(tok::l_paren)) { | ||||
275 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) | ||||
276 | << PragmaName; | ||||
277 | return; | ||||
278 | } | ||||
279 | PP.Lex(Tok); // Consume the l_paren. | ||||
280 | if (Tok.isNot(tok::identifier)) { | ||||
281 | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); | ||||
282 | return; | ||||
283 | } | ||||
284 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
285 | tok::OnOffSwitch OOS; | ||||
286 | if (II->isStr("on")) { | ||||
287 | OOS = tok::OOS_ON; | ||||
288 | PP.Lex(Tok); | ||||
289 | } else if (II->isStr("off")) { | ||||
290 | OOS = tok::OOS_OFF; | ||||
291 | PP.Lex(Tok); | ||||
292 | } else { | ||||
293 | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); | ||||
294 | return; | ||||
295 | } | ||||
296 | if (Tok.isNot(tok::r_paren)) { | ||||
297 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | ||||
298 | << PragmaName; | ||||
299 | return; | ||||
300 | } | ||||
301 | PP.Lex(Tok); // Consume the r_paren. | ||||
302 | |||||
303 | if (Tok.isNot(tok::eod)) { | ||||
304 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
305 | << PragmaName; | ||||
306 | return; | ||||
307 | } | ||||
308 | |||||
309 | MutableArrayRef<Token> Toks( | ||||
310 | PP.getPreprocessorAllocator().Allocate<Token>(1), 1); | ||||
311 | Toks[0].startToken(); | ||||
312 | Toks[0].setKind(tok::annot_pragma_fenv_access_ms); | ||||
313 | Toks[0].setLocation(FirstToken.getLocation()); | ||||
314 | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | ||||
315 | Toks[0].setAnnotationValue( | ||||
316 | reinterpret_cast<void*>(static_cast<uintptr_t>(OOS))); | ||||
317 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
318 | /*IsReinject=*/false); | ||||
319 | } | ||||
320 | }; | ||||
321 | |||||
322 | struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { | ||||
323 | PragmaForceCUDAHostDeviceHandler(Sema &Actions) | ||||
324 | : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} | ||||
325 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
326 | Token &FirstToken) override; | ||||
327 | |||||
328 | private: | ||||
329 | Sema &Actions; | ||||
330 | }; | ||||
331 | |||||
332 | /// PragmaAttributeHandler - "\#pragma clang attribute ...". | ||||
333 | struct PragmaAttributeHandler : public PragmaHandler { | ||||
334 | PragmaAttributeHandler(AttributeFactory &AttrFactory) | ||||
335 | : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {} | ||||
336 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
337 | Token &FirstToken) override; | ||||
338 | |||||
339 | /// A pool of attributes that were parsed in \#pragma clang attribute. | ||||
340 | ParsedAttributes AttributesForPragmaAttribute; | ||||
341 | }; | ||||
342 | |||||
343 | struct PragmaMaxTokensHereHandler : public PragmaHandler { | ||||
344 | PragmaMaxTokensHereHandler() : PragmaHandler("max_tokens_here") {} | ||||
345 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
346 | Token &FirstToken) override; | ||||
347 | }; | ||||
348 | |||||
349 | struct PragmaMaxTokensTotalHandler : public PragmaHandler { | ||||
350 | PragmaMaxTokensTotalHandler() : PragmaHandler("max_tokens_total") {} | ||||
351 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
352 | Token &FirstToken) override; | ||||
353 | }; | ||||
354 | |||||
355 | struct PragmaRISCVHandler : public PragmaHandler { | ||||
356 | PragmaRISCVHandler(Sema &Actions) | ||||
357 | : PragmaHandler("riscv"), Actions(Actions) {} | ||||
358 | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||||
359 | Token &FirstToken) override; | ||||
360 | |||||
361 | private: | ||||
362 | Sema &Actions; | ||||
363 | }; | ||||
364 | |||||
365 | void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) { | ||||
366 | for (auto &T : Toks) | ||||
367 | T.setFlag(clang::Token::IsReinjected); | ||||
368 | } | ||||
369 | } // end namespace | ||||
370 | |||||
371 | void Parser::initializePragmaHandlers() { | ||||
372 | AlignHandler = std::make_unique<PragmaAlignHandler>(); | ||||
373 | PP.AddPragmaHandler(AlignHandler.get()); | ||||
374 | |||||
375 | GCCVisibilityHandler = std::make_unique<PragmaGCCVisibilityHandler>(); | ||||
376 | PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); | ||||
377 | |||||
378 | OptionsHandler = std::make_unique<PragmaOptionsHandler>(); | ||||
379 | PP.AddPragmaHandler(OptionsHandler.get()); | ||||
380 | |||||
381 | PackHandler = std::make_unique<PragmaPackHandler>(); | ||||
382 | PP.AddPragmaHandler(PackHandler.get()); | ||||
383 | |||||
384 | MSStructHandler = std::make_unique<PragmaMSStructHandler>(); | ||||
385 | PP.AddPragmaHandler(MSStructHandler.get()); | ||||
386 | |||||
387 | UnusedHandler = std::make_unique<PragmaUnusedHandler>(); | ||||
388 | PP.AddPragmaHandler(UnusedHandler.get()); | ||||
389 | |||||
390 | WeakHandler = std::make_unique<PragmaWeakHandler>(); | ||||
391 | PP.AddPragmaHandler(WeakHandler.get()); | ||||
392 | |||||
393 | RedefineExtnameHandler = std::make_unique<PragmaRedefineExtnameHandler>(); | ||||
394 | PP.AddPragmaHandler(RedefineExtnameHandler.get()); | ||||
395 | |||||
396 | FPContractHandler = std::make_unique<PragmaFPContractHandler>(); | ||||
397 | PP.AddPragmaHandler("STDC", FPContractHandler.get()); | ||||
398 | |||||
399 | STDCFenvAccessHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>(); | ||||
400 | PP.AddPragmaHandler("STDC", STDCFenvAccessHandler.get()); | ||||
401 | |||||
402 | STDCFenvRoundHandler = std::make_unique<PragmaSTDC_FENV_ROUNDHandler>(); | ||||
403 | PP.AddPragmaHandler("STDC", STDCFenvRoundHandler.get()); | ||||
404 | |||||
405 | STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>(); | ||||
406 | PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get()); | ||||
407 | |||||
408 | STDCUnknownHandler = std::make_unique<PragmaSTDC_UnknownHandler>(); | ||||
409 | PP.AddPragmaHandler("STDC", STDCUnknownHandler.get()); | ||||
410 | |||||
411 | PCSectionHandler = std::make_unique<PragmaClangSectionHandler>(Actions); | ||||
412 | PP.AddPragmaHandler("clang", PCSectionHandler.get()); | ||||
413 | |||||
414 | if (getLangOpts().OpenCL) { | ||||
415 | OpenCLExtensionHandler = std::make_unique<PragmaOpenCLExtensionHandler>(); | ||||
416 | PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); | ||||
417 | |||||
418 | PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); | ||||
419 | } | ||||
420 | if (getLangOpts().OpenMP) | ||||
421 | OpenMPHandler = std::make_unique<PragmaOpenMPHandler>(); | ||||
422 | else | ||||
423 | OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>(); | ||||
424 | PP.AddPragmaHandler(OpenMPHandler.get()); | ||||
425 | |||||
426 | if (getLangOpts().MicrosoftExt || | ||||
427 | getTargetInfo().getTriple().isOSBinFormatELF()) { | ||||
428 | MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions); | ||||
429 | PP.AddPragmaHandler(MSCommentHandler.get()); | ||||
430 | } | ||||
431 | |||||
432 | FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(Actions); | ||||
433 | PP.AddPragmaHandler(FloatControlHandler.get()); | ||||
434 | if (getLangOpts().MicrosoftExt) { | ||||
435 | MSDetectMismatchHandler = | ||||
436 | std::make_unique<PragmaDetectMismatchHandler>(Actions); | ||||
437 | PP.AddPragmaHandler(MSDetectMismatchHandler.get()); | ||||
438 | MSPointersToMembers = std::make_unique<PragmaMSPointersToMembers>(); | ||||
439 | PP.AddPragmaHandler(MSPointersToMembers.get()); | ||||
440 | MSVtorDisp = std::make_unique<PragmaMSVtorDisp>(); | ||||
441 | PP.AddPragmaHandler(MSVtorDisp.get()); | ||||
442 | MSInitSeg = std::make_unique<PragmaMSPragma>("init_seg"); | ||||
443 | PP.AddPragmaHandler(MSInitSeg.get()); | ||||
444 | MSDataSeg = std::make_unique<PragmaMSPragma>("data_seg"); | ||||
445 | PP.AddPragmaHandler(MSDataSeg.get()); | ||||
446 | MSBSSSeg = std::make_unique<PragmaMSPragma>("bss_seg"); | ||||
447 | PP.AddPragmaHandler(MSBSSSeg.get()); | ||||
448 | MSConstSeg = std::make_unique<PragmaMSPragma>("const_seg"); | ||||
449 | PP.AddPragmaHandler(MSConstSeg.get()); | ||||
450 | MSCodeSeg = std::make_unique<PragmaMSPragma>("code_seg"); | ||||
451 | PP.AddPragmaHandler(MSCodeSeg.get()); | ||||
452 | MSSection = std::make_unique<PragmaMSPragma>("section"); | ||||
453 | PP.AddPragmaHandler(MSSection.get()); | ||||
454 | MSStrictGuardStackCheck = | ||||
455 | std::make_unique<PragmaMSPragma>("strict_gs_check"); | ||||
456 | PP.AddPragmaHandler(MSStrictGuardStackCheck.get()); | ||||
457 | MSFunction = std::make_unique<PragmaMSPragma>("function"); | ||||
458 | PP.AddPragmaHandler(MSFunction.get()); | ||||
459 | MSAllocText = std::make_unique<PragmaMSPragma>("alloc_text"); | ||||
460 | PP.AddPragmaHandler(MSAllocText.get()); | ||||
461 | MSOptimize = std::make_unique<PragmaMSPragma>("optimize"); | ||||
462 | PP.AddPragmaHandler(MSOptimize.get()); | ||||
463 | MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>(); | ||||
464 | PP.AddPragmaHandler(MSRuntimeChecks.get()); | ||||
465 | MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>(); | ||||
466 | PP.AddPragmaHandler(MSIntrinsic.get()); | ||||
467 | MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>(); | ||||
468 | PP.AddPragmaHandler(MSFenvAccess.get()); | ||||
469 | } | ||||
470 | |||||
471 | if (getLangOpts().CUDA) { | ||||
472 | CUDAForceHostDeviceHandler = | ||||
473 | std::make_unique<PragmaForceCUDAHostDeviceHandler>(Actions); | ||||
474 | PP.AddPragmaHandler("clang", CUDAForceHostDeviceHandler.get()); | ||||
475 | } | ||||
476 | |||||
477 | OptimizeHandler = std::make_unique<PragmaOptimizeHandler>(Actions); | ||||
478 | PP.AddPragmaHandler("clang", OptimizeHandler.get()); | ||||
479 | |||||
480 | LoopHintHandler = std::make_unique<PragmaLoopHintHandler>(); | ||||
481 | PP.AddPragmaHandler("clang", LoopHintHandler.get()); | ||||
482 | |||||
483 | UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll"); | ||||
484 | PP.AddPragmaHandler(UnrollHintHandler.get()); | ||||
485 | PP.AddPragmaHandler("GCC", UnrollHintHandler.get()); | ||||
486 | |||||
487 | NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("nounroll"); | ||||
488 | PP.AddPragmaHandler(NoUnrollHintHandler.get()); | ||||
489 | PP.AddPragmaHandler("GCC", NoUnrollHintHandler.get()); | ||||
490 | |||||
491 | UnrollAndJamHintHandler = | ||||
492 | std::make_unique<PragmaUnrollHintHandler>("unroll_and_jam"); | ||||
493 | PP.AddPragmaHandler(UnrollAndJamHintHandler.get()); | ||||
494 | |||||
495 | NoUnrollAndJamHintHandler = | ||||
496 | std::make_unique<PragmaUnrollHintHandler>("nounroll_and_jam"); | ||||
497 | PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get()); | ||||
498 | |||||
499 | FPHandler = std::make_unique<PragmaFPHandler>(); | ||||
500 | PP.AddPragmaHandler("clang", FPHandler.get()); | ||||
501 | |||||
502 | AttributePragmaHandler = | ||||
503 | std::make_unique<PragmaAttributeHandler>(AttrFactory); | ||||
504 | PP.AddPragmaHandler("clang", AttributePragmaHandler.get()); | ||||
505 | |||||
506 | MaxTokensHerePragmaHandler = std::make_unique<PragmaMaxTokensHereHandler>(); | ||||
507 | PP.AddPragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | ||||
508 | |||||
509 | MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>(); | ||||
510 | PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | ||||
511 | |||||
512 | if (getTargetInfo().getTriple().isRISCV()) { | ||||
513 | RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions); | ||||
514 | PP.AddPragmaHandler("clang", RISCVPragmaHandler.get()); | ||||
515 | } | ||||
516 | } | ||||
517 | |||||
518 | void Parser::resetPragmaHandlers() { | ||||
519 | // Remove the pragma handlers we installed. | ||||
520 | PP.RemovePragmaHandler(AlignHandler.get()); | ||||
521 | AlignHandler.reset(); | ||||
522 | PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get()); | ||||
523 | GCCVisibilityHandler.reset(); | ||||
524 | PP.RemovePragmaHandler(OptionsHandler.get()); | ||||
525 | OptionsHandler.reset(); | ||||
526 | PP.RemovePragmaHandler(PackHandler.get()); | ||||
527 | PackHandler.reset(); | ||||
528 | PP.RemovePragmaHandler(MSStructHandler.get()); | ||||
529 | MSStructHandler.reset(); | ||||
530 | PP.RemovePragmaHandler(UnusedHandler.get()); | ||||
531 | UnusedHandler.reset(); | ||||
532 | PP.RemovePragmaHandler(WeakHandler.get()); | ||||
533 | WeakHandler.reset(); | ||||
534 | PP.RemovePragmaHandler(RedefineExtnameHandler.get()); | ||||
535 | RedefineExtnameHandler.reset(); | ||||
536 | |||||
537 | if (getLangOpts().OpenCL) { | ||||
538 | PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); | ||||
539 | OpenCLExtensionHandler.reset(); | ||||
540 | PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); | ||||
541 | } | ||||
542 | PP.RemovePragmaHandler(OpenMPHandler.get()); | ||||
543 | OpenMPHandler.reset(); | ||||
544 | |||||
545 | if (getLangOpts().MicrosoftExt || | ||||
546 | getTargetInfo().getTriple().isOSBinFormatELF()) { | ||||
547 | PP.RemovePragmaHandler(MSCommentHandler.get()); | ||||
548 | MSCommentHandler.reset(); | ||||
549 | } | ||||
550 | |||||
551 | PP.RemovePragmaHandler("clang", PCSectionHandler.get()); | ||||
552 | PCSectionHandler.reset(); | ||||
553 | |||||
554 | PP.RemovePragmaHandler(FloatControlHandler.get()); | ||||
555 | FloatControlHandler.reset(); | ||||
556 | if (getLangOpts().MicrosoftExt) { | ||||
557 | PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); | ||||
558 | MSDetectMismatchHandler.reset(); | ||||
559 | PP.RemovePragmaHandler(MSPointersToMembers.get()); | ||||
560 | MSPointersToMembers.reset(); | ||||
561 | PP.RemovePragmaHandler(MSVtorDisp.get()); | ||||
562 | MSVtorDisp.reset(); | ||||
563 | PP.RemovePragmaHandler(MSInitSeg.get()); | ||||
564 | MSInitSeg.reset(); | ||||
565 | PP.RemovePragmaHandler(MSDataSeg.get()); | ||||
566 | MSDataSeg.reset(); | ||||
567 | PP.RemovePragmaHandler(MSBSSSeg.get()); | ||||
568 | MSBSSSeg.reset(); | ||||
569 | PP.RemovePragmaHandler(MSConstSeg.get()); | ||||
570 | MSConstSeg.reset(); | ||||
571 | PP.RemovePragmaHandler(MSCodeSeg.get()); | ||||
572 | MSCodeSeg.reset(); | ||||
573 | PP.RemovePragmaHandler(MSSection.get()); | ||||
574 | MSSection.reset(); | ||||
575 | PP.RemovePragmaHandler(MSStrictGuardStackCheck.get()); | ||||
576 | MSStrictGuardStackCheck.reset(); | ||||
577 | PP.RemovePragmaHandler(MSFunction.get()); | ||||
578 | MSFunction.reset(); | ||||
579 | PP.RemovePragmaHandler(MSAllocText.get()); | ||||
580 | MSAllocText.reset(); | ||||
581 | PP.RemovePragmaHandler(MSRuntimeChecks.get()); | ||||
582 | MSRuntimeChecks.reset(); | ||||
583 | PP.RemovePragmaHandler(MSIntrinsic.get()); | ||||
584 | MSIntrinsic.reset(); | ||||
585 | PP.RemovePragmaHandler(MSOptimize.get()); | ||||
586 | MSOptimize.reset(); | ||||
587 | PP.RemovePragmaHandler(MSFenvAccess.get()); | ||||
588 | MSFenvAccess.reset(); | ||||
589 | } | ||||
590 | |||||
591 | if (getLangOpts().CUDA) { | ||||
592 | PP.RemovePragmaHandler("clang", CUDAForceHostDeviceHandler.get()); | ||||
593 | CUDAForceHostDeviceHandler.reset(); | ||||
594 | } | ||||
595 | |||||
596 | PP.RemovePragmaHandler("STDC", FPContractHandler.get()); | ||||
597 | FPContractHandler.reset(); | ||||
598 | |||||
599 | PP.RemovePragmaHandler("STDC", STDCFenvAccessHandler.get()); | ||||
600 | STDCFenvAccessHandler.reset(); | ||||
601 | |||||
602 | PP.RemovePragmaHandler("STDC", STDCFenvRoundHandler.get()); | ||||
603 | STDCFenvRoundHandler.reset(); | ||||
604 | |||||
605 | PP.RemovePragmaHandler("STDC", STDCCXLIMITHandler.get()); | ||||
606 | STDCCXLIMITHandler.reset(); | ||||
607 | |||||
608 | PP.RemovePragmaHandler("STDC", STDCUnknownHandler.get()); | ||||
609 | STDCUnknownHandler.reset(); | ||||
610 | |||||
611 | PP.RemovePragmaHandler("clang", OptimizeHandler.get()); | ||||
612 | OptimizeHandler.reset(); | ||||
613 | |||||
614 | PP.RemovePragmaHandler("clang", LoopHintHandler.get()); | ||||
615 | LoopHintHandler.reset(); | ||||
616 | |||||
617 | PP.RemovePragmaHandler(UnrollHintHandler.get()); | ||||
618 | PP.RemovePragmaHandler("GCC", UnrollHintHandler.get()); | ||||
619 | UnrollHintHandler.reset(); | ||||
620 | |||||
621 | PP.RemovePragmaHandler(NoUnrollHintHandler.get()); | ||||
622 | PP.RemovePragmaHandler("GCC", NoUnrollHintHandler.get()); | ||||
623 | NoUnrollHintHandler.reset(); | ||||
624 | |||||
625 | PP.RemovePragmaHandler(UnrollAndJamHintHandler.get()); | ||||
626 | UnrollAndJamHintHandler.reset(); | ||||
627 | |||||
628 | PP.RemovePragmaHandler(NoUnrollAndJamHintHandler.get()); | ||||
629 | NoUnrollAndJamHintHandler.reset(); | ||||
630 | |||||
631 | PP.RemovePragmaHandler("clang", FPHandler.get()); | ||||
632 | FPHandler.reset(); | ||||
633 | |||||
634 | PP.RemovePragmaHandler("clang", AttributePragmaHandler.get()); | ||||
635 | AttributePragmaHandler.reset(); | ||||
636 | |||||
637 | PP.RemovePragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | ||||
638 | MaxTokensHerePragmaHandler.reset(); | ||||
639 | |||||
640 | PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | ||||
641 | MaxTokensTotalPragmaHandler.reset(); | ||||
642 | |||||
643 | if (getTargetInfo().getTriple().isRISCV()) { | ||||
644 | PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get()); | ||||
645 | RISCVPragmaHandler.reset(); | ||||
646 | } | ||||
647 | } | ||||
648 | |||||
649 | /// Handle the annotation token produced for #pragma unused(...) | ||||
650 | /// | ||||
651 | /// Each annot_pragma_unused is followed by the argument token so e.g. | ||||
652 | /// "#pragma unused(x,y)" becomes: | ||||
653 | /// annot_pragma_unused 'x' annot_pragma_unused 'y' | ||||
654 | void Parser::HandlePragmaUnused() { | ||||
655 | assert(Tok.is(tok::annot_pragma_unused))(static_cast <bool> (Tok.is(tok::annot_pragma_unused)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_unused)" , "clang/lib/Parse/ParsePragma.cpp", 655, __extension__ __PRETTY_FUNCTION__ )); | ||||
656 | SourceLocation UnusedLoc = ConsumeAnnotationToken(); | ||||
657 | Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc); | ||||
658 | ConsumeToken(); // The argument token. | ||||
659 | } | ||||
660 | |||||
661 | void Parser::HandlePragmaVisibility() { | ||||
662 | assert(Tok.is(tok::annot_pragma_vis))(static_cast <bool> (Tok.is(tok::annot_pragma_vis)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_vis)", "clang/lib/Parse/ParsePragma.cpp" , 662, __extension__ __PRETTY_FUNCTION__)); | ||||
663 | const IdentifierInfo *VisType = | ||||
664 | static_cast<IdentifierInfo *>(Tok.getAnnotationValue()); | ||||
665 | SourceLocation VisLoc = ConsumeAnnotationToken(); | ||||
666 | Actions.ActOnPragmaVisibility(VisType, VisLoc); | ||||
667 | } | ||||
668 | |||||
669 | void Parser::HandlePragmaPack() { | ||||
670 | assert(Tok.is(tok::annot_pragma_pack))(static_cast <bool> (Tok.is(tok::annot_pragma_pack)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_pack)", "clang/lib/Parse/ParsePragma.cpp" , 670, __extension__ __PRETTY_FUNCTION__)); | ||||
671 | Sema::PragmaPackInfo *Info = | ||||
672 | static_cast<Sema::PragmaPackInfo *>(Tok.getAnnotationValue()); | ||||
673 | SourceLocation PragmaLoc = Tok.getLocation(); | ||||
674 | ExprResult Alignment; | ||||
675 | if (Info->Alignment.is(tok::numeric_constant)) { | ||||
676 | Alignment = Actions.ActOnNumericConstant(Info->Alignment); | ||||
677 | if (Alignment.isInvalid()) { | ||||
678 | ConsumeAnnotationToken(); | ||||
679 | return; | ||||
680 | } | ||||
681 | } | ||||
682 | Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel, | ||||
683 | Alignment.get()); | ||||
684 | // Consume the token after processing the pragma to enable pragma-specific | ||||
685 | // #include warnings. | ||||
686 | ConsumeAnnotationToken(); | ||||
687 | } | ||||
688 | |||||
689 | void Parser::HandlePragmaMSStruct() { | ||||
690 | assert(Tok.is(tok::annot_pragma_msstruct))(static_cast <bool> (Tok.is(tok::annot_pragma_msstruct) ) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_msstruct)" , "clang/lib/Parse/ParsePragma.cpp", 690, __extension__ __PRETTY_FUNCTION__ )); | ||||
691 | PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>( | ||||
692 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
693 | Actions.ActOnPragmaMSStruct(Kind); | ||||
694 | ConsumeAnnotationToken(); | ||||
695 | } | ||||
696 | |||||
697 | void Parser::HandlePragmaAlign() { | ||||
698 | assert(Tok.is(tok::annot_pragma_align))(static_cast <bool> (Tok.is(tok::annot_pragma_align)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_align)", "clang/lib/Parse/ParsePragma.cpp", 698, __extension__ __PRETTY_FUNCTION__ )); | ||||
699 | Sema::PragmaOptionsAlignKind Kind = | ||||
700 | static_cast<Sema::PragmaOptionsAlignKind>( | ||||
701 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
702 | Actions.ActOnPragmaOptionsAlign(Kind, Tok.getLocation()); | ||||
703 | // Consume the token after processing the pragma to enable pragma-specific | ||||
704 | // #include warnings. | ||||
705 | ConsumeAnnotationToken(); | ||||
706 | } | ||||
707 | |||||
708 | void Parser::HandlePragmaDump() { | ||||
709 | assert(Tok.is(tok::annot_pragma_dump))(static_cast <bool> (Tok.is(tok::annot_pragma_dump)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_dump)", "clang/lib/Parse/ParsePragma.cpp" , 709, __extension__ __PRETTY_FUNCTION__)); | ||||
710 | ConsumeAnnotationToken(); | ||||
711 | if (Tok.is(tok::eod)) { | ||||
712 | PP.Diag(Tok, diag::warn_pragma_debug_missing_argument) << "dump"; | ||||
713 | } else if (NextToken().is(tok::eod)) { | ||||
714 | if (Tok.isNot(tok::identifier)) { | ||||
715 | PP.Diag(Tok, diag::warn_pragma_debug_unexpected_argument); | ||||
716 | ConsumeAnyToken(); | ||||
717 | ExpectAndConsume(tok::eod); | ||||
718 | return; | ||||
719 | } | ||||
720 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
721 | Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II); | ||||
722 | ConsumeToken(); | ||||
723 | } else { | ||||
724 | SourceLocation StartLoc = Tok.getLocation(); | ||||
725 | EnterExpressionEvaluationContext Ctx( | ||||
726 | Actions, Sema::ExpressionEvaluationContext::Unevaluated); | ||||
727 | ExprResult E = ParseExpression(); | ||||
728 | if (!E.isUsable() || E.get()->containsErrors()) { | ||||
729 | // Diagnostics were emitted during parsing. No action needed. | ||||
730 | } else if (E.get()->getDependence() != ExprDependence::None) { | ||||
731 | PP.Diag(StartLoc, diag::warn_pragma_debug_dependent_argument) | ||||
732 | << E.get()->isTypeDependent() | ||||
733 | << SourceRange(StartLoc, Tok.getLocation()); | ||||
734 | } else { | ||||
735 | Actions.ActOnPragmaDump(E.get()); | ||||
736 | } | ||||
737 | SkipUntil(tok::eod, StopBeforeMatch); | ||||
738 | } | ||||
739 | ExpectAndConsume(tok::eod); | ||||
740 | } | ||||
741 | |||||
742 | void Parser::HandlePragmaWeak() { | ||||
743 | assert(Tok.is(tok::annot_pragma_weak))(static_cast <bool> (Tok.is(tok::annot_pragma_weak)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_weak)", "clang/lib/Parse/ParsePragma.cpp" , 743, __extension__ __PRETTY_FUNCTION__)); | ||||
744 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
745 | Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc, | ||||
746 | Tok.getLocation()); | ||||
747 | ConsumeToken(); // The weak name. | ||||
748 | } | ||||
749 | |||||
750 | void Parser::HandlePragmaWeakAlias() { | ||||
751 | assert(Tok.is(tok::annot_pragma_weakalias))(static_cast <bool> (Tok.is(tok::annot_pragma_weakalias )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_weakalias)" , "clang/lib/Parse/ParsePragma.cpp", 751, __extension__ __PRETTY_FUNCTION__ )); | ||||
752 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
753 | IdentifierInfo *WeakName = Tok.getIdentifierInfo(); | ||||
754 | SourceLocation WeakNameLoc = Tok.getLocation(); | ||||
755 | ConsumeToken(); | ||||
756 | IdentifierInfo *AliasName = Tok.getIdentifierInfo(); | ||||
757 | SourceLocation AliasNameLoc = Tok.getLocation(); | ||||
758 | ConsumeToken(); | ||||
759 | Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc, | ||||
760 | WeakNameLoc, AliasNameLoc); | ||||
761 | |||||
762 | } | ||||
763 | |||||
764 | void Parser::HandlePragmaRedefineExtname() { | ||||
765 | assert(Tok.is(tok::annot_pragma_redefine_extname))(static_cast <bool> (Tok.is(tok::annot_pragma_redefine_extname )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_redefine_extname)" , "clang/lib/Parse/ParsePragma.cpp", 765, __extension__ __PRETTY_FUNCTION__ )); | ||||
766 | SourceLocation RedefLoc = ConsumeAnnotationToken(); | ||||
767 | IdentifierInfo *RedefName = Tok.getIdentifierInfo(); | ||||
768 | SourceLocation RedefNameLoc = Tok.getLocation(); | ||||
769 | ConsumeToken(); | ||||
770 | IdentifierInfo *AliasName = Tok.getIdentifierInfo(); | ||||
771 | SourceLocation AliasNameLoc = Tok.getLocation(); | ||||
772 | ConsumeToken(); | ||||
773 | Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, | ||||
774 | RedefNameLoc, AliasNameLoc); | ||||
775 | } | ||||
776 | |||||
777 | void Parser::HandlePragmaFPContract() { | ||||
778 | assert(Tok.is(tok::annot_pragma_fp_contract))(static_cast <bool> (Tok.is(tok::annot_pragma_fp_contract )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_fp_contract)" , "clang/lib/Parse/ParsePragma.cpp", 778, __extension__ __PRETTY_FUNCTION__ )); | ||||
779 | tok::OnOffSwitch OOS = | ||||
780 | static_cast<tok::OnOffSwitch>( | ||||
781 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
782 | |||||
783 | LangOptions::FPModeKind FPC; | ||||
784 | switch (OOS) { | ||||
785 | case tok::OOS_ON: | ||||
786 | FPC = LangOptions::FPM_On; | ||||
787 | break; | ||||
788 | case tok::OOS_OFF: | ||||
789 | FPC = LangOptions::FPM_Off; | ||||
790 | break; | ||||
791 | case tok::OOS_DEFAULT: | ||||
792 | FPC = getLangOpts().getDefaultFPContractMode(); | ||||
793 | break; | ||||
794 | } | ||||
795 | |||||
796 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
797 | Actions.ActOnPragmaFPContract(PragmaLoc, FPC); | ||||
798 | } | ||||
799 | |||||
800 | void Parser::HandlePragmaFloatControl() { | ||||
801 | assert(Tok.is(tok::annot_pragma_float_control))(static_cast <bool> (Tok.is(tok::annot_pragma_float_control )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_float_control)" , "clang/lib/Parse/ParsePragma.cpp", 801, __extension__ __PRETTY_FUNCTION__ )); | ||||
802 | |||||
803 | // The value that is held on the PragmaFloatControlStack encodes | ||||
804 | // the PragmaFloatControl kind and the MSStackAction kind | ||||
805 | // into a single 32-bit word. The MsStackAction is the high 16 bits | ||||
806 | // and the FloatControl is the lower 16 bits. Use shift and bit-and | ||||
807 | // to decode the parts. | ||||
808 | uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); | ||||
809 | Sema::PragmaMsStackAction Action = | ||||
810 | static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); | ||||
811 | PragmaFloatControlKind Kind = PragmaFloatControlKind(Value & 0xFFFF); | ||||
812 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
813 | Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind); | ||||
814 | } | ||||
815 | |||||
816 | void Parser::HandlePragmaFEnvAccess() { | ||||
817 | assert(Tok.is(tok::annot_pragma_fenv_access) ||(static_cast <bool> (Tok.is(tok::annot_pragma_fenv_access ) || Tok.is(tok::annot_pragma_fenv_access_ms)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_fenv_access) || Tok.is(tok::annot_pragma_fenv_access_ms)" , "clang/lib/Parse/ParsePragma.cpp", 818, __extension__ __PRETTY_FUNCTION__ )) | ||||
818 | Tok.is(tok::annot_pragma_fenv_access_ms))(static_cast <bool> (Tok.is(tok::annot_pragma_fenv_access ) || Tok.is(tok::annot_pragma_fenv_access_ms)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_fenv_access) || Tok.is(tok::annot_pragma_fenv_access_ms)" , "clang/lib/Parse/ParsePragma.cpp", 818, __extension__ __PRETTY_FUNCTION__ )); | ||||
819 | tok::OnOffSwitch OOS = | ||||
820 | static_cast<tok::OnOffSwitch>( | ||||
821 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
822 | |||||
823 | bool IsEnabled; | ||||
824 | switch (OOS) { | ||||
825 | case tok::OOS_ON: | ||||
826 | IsEnabled = true; | ||||
827 | break; | ||||
828 | case tok::OOS_OFF: | ||||
829 | IsEnabled = false; | ||||
830 | break; | ||||
831 | case tok::OOS_DEFAULT: // FIXME: Add this cli option when it makes sense. | ||||
832 | IsEnabled = false; | ||||
833 | break; | ||||
834 | } | ||||
835 | |||||
836 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
837 | Actions.ActOnPragmaFEnvAccess(PragmaLoc, IsEnabled); | ||||
838 | } | ||||
839 | |||||
840 | void Parser::HandlePragmaFEnvRound() { | ||||
841 | assert(Tok.is(tok::annot_pragma_fenv_round))(static_cast <bool> (Tok.is(tok::annot_pragma_fenv_round )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_fenv_round)" , "clang/lib/Parse/ParsePragma.cpp", 841, __extension__ __PRETTY_FUNCTION__ )); | ||||
842 | auto RM = static_cast<llvm::RoundingMode>( | ||||
843 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
844 | |||||
845 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
846 | Actions.ActOnPragmaFEnvRound(PragmaLoc, RM); | ||||
847 | } | ||||
848 | |||||
849 | StmtResult Parser::HandlePragmaCaptured() | ||||
850 | { | ||||
851 | assert(Tok.is(tok::annot_pragma_captured))(static_cast <bool> (Tok.is(tok::annot_pragma_captured) ) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_captured)" , "clang/lib/Parse/ParsePragma.cpp", 851, __extension__ __PRETTY_FUNCTION__ )); | ||||
852 | ConsumeAnnotationToken(); | ||||
853 | |||||
854 | if (Tok.isNot(tok::l_brace)) { | ||||
855 | PP.Diag(Tok, diag::err_expected) << tok::l_brace; | ||||
856 | return StmtError(); | ||||
857 | } | ||||
858 | |||||
859 | SourceLocation Loc = Tok.getLocation(); | ||||
860 | |||||
861 | ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope | | ||||
862 | Scope::CompoundStmtScope); | ||||
863 | Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, | ||||
864 | /*NumParams=*/1); | ||||
865 | |||||
866 | StmtResult R = ParseCompoundStatement(); | ||||
867 | CapturedRegionScope.Exit(); | ||||
868 | |||||
869 | if (R.isInvalid()) { | ||||
870 | Actions.ActOnCapturedRegionError(); | ||||
871 | return StmtError(); | ||||
872 | } | ||||
873 | |||||
874 | return Actions.ActOnCapturedRegionEnd(R.get()); | ||||
875 | } | ||||
876 | |||||
877 | namespace { | ||||
878 | enum OpenCLExtState : char { | ||||
879 | Disable, Enable, Begin, End | ||||
880 | }; | ||||
881 | typedef std::pair<const IdentifierInfo *, OpenCLExtState> OpenCLExtData; | ||||
882 | } | ||||
883 | |||||
884 | void Parser::HandlePragmaOpenCLExtension() { | ||||
885 | assert(Tok.is(tok::annot_pragma_opencl_extension))(static_cast <bool> (Tok.is(tok::annot_pragma_opencl_extension )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_opencl_extension)" , "clang/lib/Parse/ParsePragma.cpp", 885, __extension__ __PRETTY_FUNCTION__ )); | ||||
886 | OpenCLExtData *Data = static_cast<OpenCLExtData*>(Tok.getAnnotationValue()); | ||||
887 | auto State = Data->second; | ||||
888 | auto Ident = Data->first; | ||||
889 | SourceLocation NameLoc = Tok.getLocation(); | ||||
890 | ConsumeAnnotationToken(); | ||||
891 | |||||
892 | auto &Opt = Actions.getOpenCLOptions(); | ||||
893 | auto Name = Ident->getName(); | ||||
894 | // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, | ||||
895 | // overriding all previously issued extension directives, but only if the | ||||
896 | // behavior is set to disable." | ||||
897 | if (Name == "all") { | ||||
898 | if (State == Disable) | ||||
899 | Opt.disableAll(); | ||||
900 | else | ||||
901 | PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1; | ||||
902 | } else if (State == Begin) { | ||||
903 | if (!Opt.isKnown(Name) || !Opt.isSupported(Name, getLangOpts())) { | ||||
904 | Opt.support(Name); | ||||
905 | // FIXME: Default behavior of the extension pragma is not defined. | ||||
906 | // Therefore, it should never be added by default. | ||||
907 | Opt.acceptsPragma(Name); | ||||
908 | } | ||||
909 | } else if (State == End) { | ||||
910 | // There is no behavior for this directive. We only accept this for | ||||
911 | // backward compatibility. | ||||
912 | } else if (!Opt.isKnown(Name) || !Opt.isWithPragma(Name)) | ||||
913 | PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; | ||||
914 | else if (Opt.isSupportedExtension(Name, getLangOpts())) | ||||
915 | Opt.enable(Name, State == Enable); | ||||
916 | else if (Opt.isSupportedCoreOrOptionalCore(Name, getLangOpts())) | ||||
917 | PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << Ident; | ||||
918 | else | ||||
919 | PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << Ident; | ||||
920 | } | ||||
921 | |||||
922 | void Parser::HandlePragmaMSPointersToMembers() { | ||||
923 | assert(Tok.is(tok::annot_pragma_ms_pointers_to_members))(static_cast <bool> (Tok.is(tok::annot_pragma_ms_pointers_to_members )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_ms_pointers_to_members)" , "clang/lib/Parse/ParsePragma.cpp", 923, __extension__ __PRETTY_FUNCTION__ )); | ||||
924 | LangOptions::PragmaMSPointersToMembersKind RepresentationMethod = | ||||
925 | static_cast<LangOptions::PragmaMSPointersToMembersKind>( | ||||
926 | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | ||||
927 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
928 | Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc); | ||||
929 | } | ||||
930 | |||||
931 | void Parser::HandlePragmaMSVtorDisp() { | ||||
932 | assert(Tok.is(tok::annot_pragma_ms_vtordisp))(static_cast <bool> (Tok.is(tok::annot_pragma_ms_vtordisp )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_ms_vtordisp)" , "clang/lib/Parse/ParsePragma.cpp", 932, __extension__ __PRETTY_FUNCTION__ )); | ||||
933 | uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); | ||||
934 | Sema::PragmaMsStackAction Action = | ||||
935 | static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); | ||||
936 | MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF); | ||||
937 | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | ||||
938 | Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode); | ||||
939 | } | ||||
940 | |||||
941 | void Parser::HandlePragmaMSPragma() { | ||||
942 | assert(Tok.is(tok::annot_pragma_ms_pragma))(static_cast <bool> (Tok.is(tok::annot_pragma_ms_pragma )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_ms_pragma)" , "clang/lib/Parse/ParsePragma.cpp", 942, __extension__ __PRETTY_FUNCTION__ )); | ||||
943 | // Grab the tokens out of the annotation and enter them into the stream. | ||||
944 | auto TheTokens = | ||||
945 | (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue(); | ||||
946 | PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true, | ||||
947 | /*IsReinject=*/true); | ||||
948 | SourceLocation PragmaLocation = ConsumeAnnotationToken(); | ||||
949 | assert(Tok.isAnyIdentifier())(static_cast <bool> (Tok.isAnyIdentifier()) ? void (0) : __assert_fail ("Tok.isAnyIdentifier()", "clang/lib/Parse/ParsePragma.cpp" , 949, __extension__ __PRETTY_FUNCTION__)); | ||||
950 | StringRef PragmaName = Tok.getIdentifierInfo()->getName(); | ||||
951 | PP.Lex(Tok); // pragma kind | ||||
952 | |||||
953 | // Figure out which #pragma we're dealing with. The switch has no default | ||||
954 | // because lex shouldn't emit the annotation token for unrecognized pragmas. | ||||
955 | typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation); | ||||
956 | PragmaHandler Handler = | ||||
957 | llvm::StringSwitch<PragmaHandler>(PragmaName) | ||||
958 | .Case("data_seg", &Parser::HandlePragmaMSSegment) | ||||
959 | .Case("bss_seg", &Parser::HandlePragmaMSSegment) | ||||
960 | .Case("const_seg", &Parser::HandlePragmaMSSegment) | ||||
961 | .Case("code_seg", &Parser::HandlePragmaMSSegment) | ||||
962 | .Case("section", &Parser::HandlePragmaMSSection) | ||||
963 | .Case("init_seg", &Parser::HandlePragmaMSInitSeg) | ||||
964 | .Case("strict_gs_check", &Parser::HandlePragmaMSStrictGuardStackCheck) | ||||
965 | .Case("function", &Parser::HandlePragmaMSFunction) | ||||
966 | .Case("alloc_text", &Parser::HandlePragmaMSAllocText) | ||||
967 | .Case("optimize", &Parser::HandlePragmaMSOptimize); | ||||
968 | |||||
969 | if (!(this->*Handler)(PragmaName, PragmaLocation)) { | ||||
970 | // Pragma handling failed, and has been diagnosed. Slurp up the tokens | ||||
971 | // until eof (really end of line) to prevent follow-on errors. | ||||
972 | while (Tok.isNot(tok::eof)) | ||||
973 | PP.Lex(Tok); | ||||
974 | PP.Lex(Tok); | ||||
975 | } | ||||
976 | } | ||||
977 | |||||
978 | bool Parser::HandlePragmaMSSection(StringRef PragmaName, | ||||
979 | SourceLocation PragmaLocation) { | ||||
980 | if (Tok.isNot(tok::l_paren)) { | ||||
981 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName; | ||||
982 | return false; | ||||
983 | } | ||||
984 | PP.Lex(Tok); // ( | ||||
985 | // Parsing code for pragma section | ||||
986 | if (Tok.isNot(tok::string_literal)) { | ||||
987 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name) | ||||
988 | << PragmaName; | ||||
989 | return false; | ||||
990 | } | ||||
991 | ExprResult StringResult = ParseStringLiteralExpression(); | ||||
992 | if (StringResult.isInvalid()) | ||||
993 | return false; // Already diagnosed. | ||||
994 | StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get()); | ||||
995 | if (SegmentName->getCharByteWidth() != 1) { | ||||
996 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | ||||
997 | << PragmaName; | ||||
998 | return false; | ||||
999 | } | ||||
1000 | int SectionFlags = ASTContext::PSF_Read; | ||||
1001 | bool SectionFlagsAreDefault = true; | ||||
1002 | while (Tok.is(tok::comma)) { | ||||
1003 | PP.Lex(Tok); // , | ||||
1004 | // Ignore "long" and "short". | ||||
1005 | // They are undocumented, but widely used, section attributes which appear | ||||
1006 | // to do nothing. | ||||
1007 | if (Tok.is(tok::kw_long) || Tok.is(tok::kw_short)) { | ||||
1008 | PP.Lex(Tok); // long/short | ||||
1009 | continue; | ||||
1010 | } | ||||
1011 | |||||
1012 | if (!Tok.isAnyIdentifier()) { | ||||
1013 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren) | ||||
1014 | << PragmaName; | ||||
1015 | return false; | ||||
1016 | } | ||||
1017 | ASTContext::PragmaSectionFlag Flag = | ||||
1018 | llvm::StringSwitch<ASTContext::PragmaSectionFlag>( | ||||
1019 | Tok.getIdentifierInfo()->getName()) | ||||
1020 | .Case("read", ASTContext::PSF_Read) | ||||
1021 | .Case("write", ASTContext::PSF_Write) | ||||
1022 | .Case("execute", ASTContext::PSF_Execute) | ||||
1023 | .Case("shared", ASTContext::PSF_Invalid) | ||||
1024 | .Case("nopage", ASTContext::PSF_Invalid) | ||||
1025 | .Case("nocache", ASTContext::PSF_Invalid) | ||||
1026 | .Case("discard", ASTContext::PSF_Invalid) | ||||
1027 | .Case("remove", ASTContext::PSF_Invalid) | ||||
1028 | .Default(ASTContext::PSF_None); | ||||
1029 | if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) { | ||||
1030 | PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None | ||||
1031 | ? diag::warn_pragma_invalid_specific_action | ||||
1032 | : diag::warn_pragma_unsupported_action) | ||||
1033 | << PragmaName << Tok.getIdentifierInfo()->getName(); | ||||
1034 | return false; | ||||
1035 | } | ||||
1036 | SectionFlags |= Flag; | ||||
1037 | SectionFlagsAreDefault = false; | ||||
1038 | PP.Lex(Tok); // Identifier | ||||
1039 | } | ||||
1040 | // If no section attributes are specified, the section will be marked as | ||||
1041 | // read/write. | ||||
1042 | if (SectionFlagsAreDefault) | ||||
1043 | SectionFlags |= ASTContext::PSF_Write; | ||||
1044 | if (Tok.isNot(tok::r_paren)) { | ||||
1045 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; | ||||
1046 | return false; | ||||
1047 | } | ||||
1048 | PP.Lex(Tok); // ) | ||||
1049 | if (Tok.isNot(tok::eof)) { | ||||
1050 | PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol) | ||||
1051 | << PragmaName; | ||||
1052 | return false; | ||||
1053 | } | ||||
1054 | PP.Lex(Tok); // eof | ||||
1055 | Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName); | ||||
1056 | return true; | ||||
1057 | } | ||||
1058 | |||||
1059 | bool Parser::HandlePragmaMSSegment(StringRef PragmaName, | ||||
1060 | SourceLocation PragmaLocation) { | ||||
1061 | if (Tok.isNot(tok::l_paren)) { | ||||
1062 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName; | ||||
1063 | return false; | ||||
1064 | } | ||||
1065 | PP.Lex(Tok); // ( | ||||
1066 | Sema::PragmaMsStackAction Action = Sema::PSK_Reset; | ||||
1067 | StringRef SlotLabel; | ||||
1068 | if (Tok.isAnyIdentifier()) { | ||||
1069 | StringRef PushPop = Tok.getIdentifierInfo()->getName(); | ||||
1070 | if (PushPop == "push") | ||||
1071 | Action = Sema::PSK_Push; | ||||
1072 | else if (PushPop == "pop") | ||||
1073 | Action = Sema::PSK_Pop; | ||||
1074 | else { | ||||
1075 | PP.Diag(PragmaLocation, | ||||
1076 | diag::warn_pragma_expected_section_push_pop_or_name) | ||||
1077 | << PragmaName; | ||||
1078 | return false; | ||||
1079 | } | ||||
1080 | if (Action != Sema::PSK_Reset) { | ||||
1081 | PP.Lex(Tok); // push | pop | ||||
1082 | if (Tok.is(tok::comma)) { | ||||
1083 | PP.Lex(Tok); // , | ||||
1084 | // If we've got a comma, we either need a label or a string. | ||||
1085 | if (Tok.isAnyIdentifier()) { | ||||
1086 | SlotLabel = Tok.getIdentifierInfo()->getName(); | ||||
1087 | PP.Lex(Tok); // identifier | ||||
1088 | if (Tok.is(tok::comma)) | ||||
1089 | PP.Lex(Tok); | ||||
1090 | else if (Tok.isNot(tok::r_paren)) { | ||||
1091 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) | ||||
1092 | << PragmaName; | ||||
1093 | return false; | ||||
1094 | } | ||||
1095 | } | ||||
1096 | } else if (Tok.isNot(tok::r_paren)) { | ||||
1097 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName; | ||||
1098 | return false; | ||||
1099 | } | ||||
1100 | } | ||||
1101 | } | ||||
1102 | // Grab the string literal for our section name. | ||||
1103 | StringLiteral *SegmentName = nullptr; | ||||
1104 | if (Tok.isNot(tok::r_paren)) { | ||||
1105 | if (Tok.isNot(tok::string_literal)) { | ||||
1106 | unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ? | ||||
1107 | diag::warn_pragma_expected_section_name : | ||||
1108 | diag::warn_pragma_expected_section_label_or_name : | ||||
1109 | diag::warn_pragma_expected_section_push_pop_or_name; | ||||
1110 | PP.Diag(PragmaLocation, DiagID) << PragmaName; | ||||
1111 | return false; | ||||
1112 | } | ||||
1113 | ExprResult StringResult = ParseStringLiteralExpression(); | ||||
1114 | if (StringResult.isInvalid()) | ||||
1115 | return false; // Already diagnosed. | ||||
1116 | SegmentName = cast<StringLiteral>(StringResult.get()); | ||||
1117 | if (SegmentName->getCharByteWidth() != 1) { | ||||
1118 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | ||||
1119 | << PragmaName; | ||||
1120 | return false; | ||||
1121 | } | ||||
1122 | // Setting section "" has no effect | ||||
1123 | if (SegmentName->getLength()) | ||||
1124 | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | ||||
1125 | } | ||||
1126 | if (Tok.isNot(tok::r_paren)) { | ||||
1127 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; | ||||
1128 | return false; | ||||
1129 | } | ||||
1130 | PP.Lex(Tok); // ) | ||||
1131 | if (Tok.isNot(tok::eof)) { | ||||
1132 | PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol) | ||||
1133 | << PragmaName; | ||||
1134 | return false; | ||||
1135 | } | ||||
1136 | PP.Lex(Tok); // eof | ||||
1137 | Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel, | ||||
1138 | SegmentName, PragmaName); | ||||
1139 | return true; | ||||
1140 | } | ||||
1141 | |||||
1142 | // #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} ) | ||||
1143 | bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName, | ||||
1144 | SourceLocation PragmaLocation) { | ||||
1145 | if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) { | ||||
1146 | PP.Diag(PragmaLocation, diag::warn_pragma_init_seg_unsupported_target); | ||||
1147 | return false; | ||||
1148 | } | ||||
1149 | |||||
1150 | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | ||||
1151 | PragmaName)) | ||||
1152 | return false; | ||||
1153 | |||||
1154 | // Parse either the known section names or the string section name. | ||||
1155 | StringLiteral *SegmentName = nullptr; | ||||
1156 | if (Tok.isAnyIdentifier()) { | ||||
1157 | auto *II = Tok.getIdentifierInfo(); | ||||
1158 | StringRef Section = llvm::StringSwitch<StringRef>(II->getName()) | ||||
1159 | .Case("compiler", "\".CRT$XCC\"") | ||||
1160 | .Case("lib", "\".CRT$XCL\"") | ||||
1161 | .Case("user", "\".CRT$XCU\"") | ||||
1162 | .Default(""); | ||||
1163 | |||||
1164 | if (!Section.empty()) { | ||||
1165 | // Pretend the user wrote the appropriate string literal here. | ||||
1166 | Token Toks[1]; | ||||
1167 | Toks[0].startToken(); | ||||
1168 | Toks[0].setKind(tok::string_literal); | ||||
1169 | Toks[0].setLocation(Tok.getLocation()); | ||||
1170 | Toks[0].setLiteralData(Section.data()); | ||||
1171 | Toks[0].setLength(Section.size()); | ||||
1172 | SegmentName = | ||||
1173 | cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get()); | ||||
1174 | PP.Lex(Tok); | ||||
1175 | } | ||||
1176 | } else if (Tok.is(tok::string_literal)) { | ||||
1177 | ExprResult StringResult = ParseStringLiteralExpression(); | ||||
1178 | if (StringResult.isInvalid()) | ||||
1179 | return false; | ||||
1180 | SegmentName = cast<StringLiteral>(StringResult.get()); | ||||
1181 | if (SegmentName->getCharByteWidth() != 1) { | ||||
1182 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | ||||
1183 | << PragmaName; | ||||
1184 | return false; | ||||
1185 | } | ||||
1186 | // FIXME: Add support for the '[, func-name]' part of the pragma. | ||||
1187 | } | ||||
1188 | |||||
1189 | if (!SegmentName) { | ||||
1190 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName; | ||||
1191 | return false; | ||||
1192 | } | ||||
1193 | |||||
1194 | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | ||||
1195 | PragmaName) || | ||||
1196 | ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | ||||
1197 | PragmaName)) | ||||
1198 | return false; | ||||
1199 | |||||
1200 | Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName); | ||||
1201 | return true; | ||||
1202 | } | ||||
1203 | |||||
1204 | // #pragma strict_gs_check(pop) | ||||
1205 | // #pragma strict_gs_check(push, "on" | "off") | ||||
1206 | // #pragma strict_gs_check("on" | "off") | ||||
1207 | bool Parser::HandlePragmaMSStrictGuardStackCheck( | ||||
1208 | StringRef PragmaName, SourceLocation PragmaLocation) { | ||||
1209 | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | ||||
1210 | PragmaName)) | ||||
1211 | return false; | ||||
1212 | |||||
1213 | Sema::PragmaMsStackAction Action = Sema::PSK_Set; | ||||
1214 | if (Tok.is(tok::identifier)) { | ||||
1215 | StringRef PushPop = Tok.getIdentifierInfo()->getName(); | ||||
1216 | if (PushPop == "push") { | ||||
1217 | PP.Lex(Tok); | ||||
1218 | Action = Sema::PSK_Push; | ||||
1219 | if (ExpectAndConsume(tok::comma, diag::warn_pragma_expected_punc, | ||||
1220 | PragmaName)) | ||||
1221 | return false; | ||||
1222 | } else if (PushPop == "pop") { | ||||
1223 | PP.Lex(Tok); | ||||
1224 | Action = Sema::PSK_Pop; | ||||
1225 | } | ||||
1226 | } | ||||
1227 | |||||
1228 | bool Value = false; | ||||
1229 | if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) { | ||||
1230 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
1231 | if (II && II->isStr("off")) { | ||||
1232 | PP.Lex(Tok); | ||||
1233 | Value = false; | ||||
1234 | } else if (II && II->isStr("on")) { | ||||
1235 | PP.Lex(Tok); | ||||
1236 | Value = true; | ||||
1237 | } else { | ||||
1238 | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) | ||||
1239 | << PragmaName; | ||||
1240 | return false; | ||||
1241 | } | ||||
1242 | } | ||||
1243 | |||||
1244 | // Finish the pragma: ')' $ | ||||
1245 | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | ||||
1246 | PragmaName)) | ||||
1247 | return false; | ||||
1248 | |||||
1249 | if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | ||||
1250 | PragmaName)) | ||||
1251 | return false; | ||||
1252 | |||||
1253 | Actions.ActOnPragmaMSStrictGuardStackCheck(PragmaLocation, Action, Value); | ||||
1254 | return true; | ||||
1255 | } | ||||
1256 | |||||
1257 | bool Parser::HandlePragmaMSAllocText(StringRef PragmaName, | ||||
1258 | SourceLocation PragmaLocation) { | ||||
1259 | Token FirstTok = Tok; | ||||
1260 | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | ||||
1261 | PragmaName)) | ||||
1262 | return false; | ||||
1263 | |||||
1264 | StringRef Section; | ||||
1265 | if (Tok.is(tok::string_literal)) { | ||||
1266 | ExprResult StringResult = ParseStringLiteralExpression(); | ||||
1267 | if (StringResult.isInvalid()) | ||||
1268 | return false; // Already diagnosed. | ||||
1269 | StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get()); | ||||
1270 | if (SegmentName->getCharByteWidth() != 1) { | ||||
1271 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | ||||
1272 | << PragmaName; | ||||
1273 | return false; | ||||
1274 | } | ||||
1275 | Section = SegmentName->getString(); | ||||
1276 | } else if (Tok.is(tok::identifier)) { | ||||
1277 | Section = Tok.getIdentifierInfo()->getName(); | ||||
1278 | PP.Lex(Tok); | ||||
1279 | } else { | ||||
1280 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name) | ||||
1281 | << PragmaName; | ||||
1282 | return false; | ||||
1283 | } | ||||
1284 | |||||
1285 | if (ExpectAndConsume(tok::comma, diag::warn_pragma_expected_comma, | ||||
1286 | PragmaName)) | ||||
1287 | return false; | ||||
1288 | |||||
1289 | SmallVector<std::tuple<IdentifierInfo *, SourceLocation>> Functions; | ||||
1290 | while (true) { | ||||
1291 | if (Tok.isNot(tok::identifier)) { | ||||
1292 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
1293 | << PragmaName; | ||||
1294 | return false; | ||||
1295 | } | ||||
1296 | |||||
1297 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
1298 | Functions.emplace_back(II, Tok.getLocation()); | ||||
1299 | |||||
1300 | PP.Lex(Tok); | ||||
1301 | if (Tok.isNot(tok::comma)) | ||||
1302 | break; | ||||
1303 | PP.Lex(Tok); | ||||
1304 | } | ||||
1305 | |||||
1306 | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | ||||
1307 | PragmaName) || | ||||
1308 | ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | ||||
1309 | PragmaName)) | ||||
1310 | return false; | ||||
1311 | |||||
1312 | Actions.ActOnPragmaMSAllocText(FirstTok.getLocation(), Section, Functions); | ||||
1313 | return true; | ||||
1314 | } | ||||
1315 | |||||
1316 | static std::string PragmaLoopHintString(Token PragmaName, Token Option) { | ||||
1317 | StringRef Str = PragmaName.getIdentifierInfo()->getName(); | ||||
1318 | std::string ClangLoopStr("clang loop "); | ||||
1319 | if (Str == "loop" && Option.getIdentifierInfo()) | ||||
1320 | ClangLoopStr += Option.getIdentifierInfo()->getName(); | ||||
1321 | return std::string(llvm::StringSwitch<StringRef>(Str) | ||||
1322 | .Case("loop", ClangLoopStr) | ||||
1323 | .Case("unroll_and_jam", Str) | ||||
1324 | .Case("unroll", Str) | ||||
1325 | .Default("")); | ||||
1326 | } | ||||
1327 | |||||
1328 | bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { | ||||
1329 | assert(Tok.is(tok::annot_pragma_loop_hint))(static_cast <bool> (Tok.is(tok::annot_pragma_loop_hint )) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_loop_hint)" , "clang/lib/Parse/ParsePragma.cpp", 1329, __extension__ __PRETTY_FUNCTION__ )); | ||||
1330 | PragmaLoopHintInfo *Info = | ||||
1331 | static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue()); | ||||
1332 | |||||
1333 | IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo(); | ||||
1334 | Hint.PragmaNameLoc = IdentifierLoc::create( | ||||
1335 | Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo); | ||||
1336 | |||||
1337 | // It is possible that the loop hint has no option identifier, such as | ||||
1338 | // #pragma unroll(4). | ||||
1339 | IdentifierInfo *OptionInfo = Info->Option.is(tok::identifier) | ||||
1340 | ? Info->Option.getIdentifierInfo() | ||||
1341 | : nullptr; | ||||
1342 | Hint.OptionLoc = IdentifierLoc::create( | ||||
1343 | Actions.Context, Info->Option.getLocation(), OptionInfo); | ||||
1344 | |||||
1345 | llvm::ArrayRef<Token> Toks = Info->Toks; | ||||
1346 | |||||
1347 | // Return a valid hint if pragma unroll or nounroll were specified | ||||
1348 | // without an argument. | ||||
1349 | auto IsLoopHint = llvm::StringSwitch<bool>(PragmaNameInfo->getName()) | ||||
1350 | .Cases("unroll", "nounroll", "unroll_and_jam", | ||||
1351 | "nounroll_and_jam", true) | ||||
1352 | .Default(false); | ||||
1353 | |||||
1354 | if (Toks.empty() && IsLoopHint) { | ||||
1355 | ConsumeAnnotationToken(); | ||||
1356 | Hint.Range = Info->PragmaName.getLocation(); | ||||
1357 | return true; | ||||
1358 | } | ||||
1359 | |||||
1360 | // The constant expression is always followed by an eof token, which increases | ||||
1361 | // the TokSize by 1. | ||||
1362 | assert(!Toks.empty() &&(static_cast <bool> (!Toks.empty() && "PragmaLoopHintInfo::Toks must contain at least one token." ) ? void (0) : __assert_fail ("!Toks.empty() && \"PragmaLoopHintInfo::Toks must contain at least one token.\"" , "clang/lib/Parse/ParsePragma.cpp", 1363, __extension__ __PRETTY_FUNCTION__ )) | ||||
1363 | "PragmaLoopHintInfo::Toks must contain at least one token.")(static_cast <bool> (!Toks.empty() && "PragmaLoopHintInfo::Toks must contain at least one token." ) ? void (0) : __assert_fail ("!Toks.empty() && \"PragmaLoopHintInfo::Toks must contain at least one token.\"" , "clang/lib/Parse/ParsePragma.cpp", 1363, __extension__ __PRETTY_FUNCTION__ )); | ||||
1364 | |||||
1365 | // If no option is specified the argument is assumed to be a constant expr. | ||||
1366 | bool OptionUnroll = false; | ||||
1367 | bool OptionUnrollAndJam = false; | ||||
1368 | bool OptionDistribute = false; | ||||
1369 | bool OptionPipelineDisabled = false; | ||||
1370 | bool StateOption = false; | ||||
1371 | if (OptionInfo) { // Pragma Unroll does not specify an option. | ||||
1372 | OptionUnroll = OptionInfo->isStr("unroll"); | ||||
1373 | OptionUnrollAndJam = OptionInfo->isStr("unroll_and_jam"); | ||||
1374 | OptionDistribute = OptionInfo->isStr("distribute"); | ||||
1375 | OptionPipelineDisabled = OptionInfo->isStr("pipeline"); | ||||
1376 | StateOption = llvm::StringSwitch<bool>(OptionInfo->getName()) | ||||
1377 | .Case("vectorize", true) | ||||
1378 | .Case("interleave", true) | ||||
1379 | .Case("vectorize_predicate", true) | ||||
1380 | .Default(false) || | ||||
1381 | OptionUnroll || OptionUnrollAndJam || OptionDistribute || | ||||
1382 | OptionPipelineDisabled; | ||||
1383 | } | ||||
1384 | |||||
1385 | bool AssumeSafetyArg = !OptionUnroll && !OptionUnrollAndJam && | ||||
1386 | !OptionDistribute && !OptionPipelineDisabled; | ||||
1387 | // Verify loop hint has an argument. | ||||
1388 | if (Toks[0].is(tok::eof)) { | ||||
1389 | ConsumeAnnotationToken(); | ||||
1390 | Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument) | ||||
1391 | << /*StateArgument=*/StateOption | ||||
1392 | << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) | ||||
1393 | << /*AssumeSafetyKeyword=*/AssumeSafetyArg; | ||||
1394 | return false; | ||||
1395 | } | ||||
1396 | |||||
1397 | // Validate the argument. | ||||
1398 | if (StateOption) { | ||||
1399 | ConsumeAnnotationToken(); | ||||
1400 | SourceLocation StateLoc = Toks[0].getLocation(); | ||||
1401 | IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); | ||||
1402 | |||||
1403 | bool Valid = StateInfo && | ||||
1404 | llvm::StringSwitch<bool>(StateInfo->getName()) | ||||
1405 | .Case("disable", true) | ||||
1406 | .Case("enable", !OptionPipelineDisabled) | ||||
1407 | .Case("full", OptionUnroll || OptionUnrollAndJam) | ||||
1408 | .Case("assume_safety", AssumeSafetyArg) | ||||
1409 | .Default(false); | ||||
1410 | if (!Valid) { | ||||
1411 | if (OptionPipelineDisabled) { | ||||
1412 | Diag(Toks[0].getLocation(), diag::err_pragma_pipeline_invalid_keyword); | ||||
1413 | } else { | ||||
1414 | Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword) | ||||
1415 | << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) | ||||
1416 | << /*AssumeSafetyKeyword=*/AssumeSafetyArg; | ||||
1417 | } | ||||
1418 | return false; | ||||
1419 | } | ||||
1420 | if (Toks.size() > 2) | ||||
1421 | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
1422 | << PragmaLoopHintString(Info->PragmaName, Info->Option); | ||||
1423 | Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); | ||||
1424 | } else if (OptionInfo && OptionInfo->getName() == "vectorize_width") { | ||||
1425 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, | ||||
1426 | /*IsReinject=*/false); | ||||
1427 | ConsumeAnnotationToken(); | ||||
1428 | |||||
1429 | SourceLocation StateLoc = Toks[0].getLocation(); | ||||
1430 | IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); | ||||
1431 | StringRef IsScalableStr = StateInfo ? StateInfo->getName() : ""; | ||||
1432 | |||||
1433 | // Look for vectorize_width(fixed|scalable) | ||||
1434 | if (IsScalableStr == "scalable" || IsScalableStr == "fixed") { | ||||
1435 | PP.Lex(Tok); // Identifier | ||||
1436 | |||||
1437 | if (Toks.size() > 2) { | ||||
1438 | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
1439 | << PragmaLoopHintString(Info->PragmaName, Info->Option); | ||||
1440 | while (Tok.isNot(tok::eof)) | ||||
1441 | ConsumeAnyToken(); | ||||
1442 | } | ||||
1443 | |||||
1444 | Hint.StateLoc = | ||||
1445 | IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); | ||||
1446 | |||||
1447 | ConsumeToken(); // Consume the constant expression eof terminator. | ||||
1448 | } else { | ||||
1449 | // Enter constant expression including eof terminator into token stream. | ||||
1450 | ExprResult R = ParseConstantExpression(); | ||||
1451 | |||||
1452 | if (R.isInvalid() && !Tok.is(tok::comma)) | ||||
1453 | Diag(Toks[0].getLocation(), | ||||
1454 | diag::note_pragma_loop_invalid_vectorize_option); | ||||
1455 | |||||
1456 | bool Arg2Error = false; | ||||
1457 | if (Tok.is(tok::comma)) { | ||||
1458 | PP.Lex(Tok); // , | ||||
1459 | |||||
1460 | StateInfo = Tok.getIdentifierInfo(); | ||||
1461 | IsScalableStr = StateInfo->getName(); | ||||
1462 | |||||
1463 | if (IsScalableStr != "scalable" && IsScalableStr != "fixed") { | ||||
1464 | Diag(Tok.getLocation(), | ||||
1465 | diag::err_pragma_loop_invalid_vectorize_option); | ||||
1466 | Arg2Error = true; | ||||
1467 | } else | ||||
1468 | Hint.StateLoc = | ||||
1469 | IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); | ||||
1470 | |||||
1471 | PP.Lex(Tok); // Identifier | ||||
1472 | } | ||||
1473 | |||||
1474 | // Tokens following an error in an ill-formed constant expression will | ||||
1475 | // remain in the token stream and must be removed. | ||||
1476 | if (Tok.isNot(tok::eof)) { | ||||
1477 | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
1478 | << PragmaLoopHintString(Info->PragmaName, Info->Option); | ||||
1479 | while (Tok.isNot(tok::eof)) | ||||
1480 | ConsumeAnyToken(); | ||||
1481 | } | ||||
1482 | |||||
1483 | ConsumeToken(); // Consume the constant expression eof terminator. | ||||
1484 | |||||
1485 | if (Arg2Error || R.isInvalid() || | ||||
1486 | Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation())) | ||||
1487 | return false; | ||||
1488 | |||||
1489 | // Argument is a constant expression with an integer type. | ||||
1490 | Hint.ValueExpr = R.get(); | ||||
1491 | } | ||||
1492 | } else { | ||||
1493 | // Enter constant expression including eof terminator into token stream. | ||||
1494 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, | ||||
1495 | /*IsReinject=*/false); | ||||
1496 | ConsumeAnnotationToken(); | ||||
1497 | ExprResult R = ParseConstantExpression(); | ||||
1498 | |||||
1499 | // Tokens following an error in an ill-formed constant expression will | ||||
1500 | // remain in the token stream and must be removed. | ||||
1501 | if (Tok.isNot(tok::eof)) { | ||||
1502 | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
1503 | << PragmaLoopHintString(Info->PragmaName, Info->Option); | ||||
1504 | while (Tok.isNot(tok::eof)) | ||||
1505 | ConsumeAnyToken(); | ||||
1506 | } | ||||
1507 | |||||
1508 | ConsumeToken(); // Consume the constant expression eof terminator. | ||||
1509 | |||||
1510 | if (R.isInvalid() || | ||||
1511 | Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation())) | ||||
1512 | return false; | ||||
1513 | |||||
1514 | // Argument is a constant expression with an integer type. | ||||
1515 | Hint.ValueExpr = R.get(); | ||||
1516 | } | ||||
1517 | |||||
1518 | Hint.Range = SourceRange(Info->PragmaName.getLocation(), | ||||
1519 | Info->Toks.back().getLocation()); | ||||
1520 | return true; | ||||
1521 | } | ||||
1522 | |||||
1523 | namespace { | ||||
1524 | struct PragmaAttributeInfo { | ||||
1525 | enum ActionType { Push, Pop, Attribute }; | ||||
1526 | ParsedAttributes &Attributes; | ||||
1527 | ActionType Action; | ||||
1528 | const IdentifierInfo *Namespace = nullptr; | ||||
1529 | ArrayRef<Token> Tokens; | ||||
1530 | |||||
1531 | PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {} | ||||
1532 | }; | ||||
1533 | |||||
1534 | #include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc" | ||||
1535 | |||||
1536 | } // end anonymous namespace | ||||
1537 | |||||
1538 | static StringRef getIdentifier(const Token &Tok) { | ||||
1539 | if (Tok.is(tok::identifier)) | ||||
1540 | return Tok.getIdentifierInfo()->getName(); | ||||
1541 | const char *S = tok::getKeywordSpelling(Tok.getKind()); | ||||
1542 | if (!S) | ||||
1543 | return ""; | ||||
1544 | return S; | ||||
1545 | } | ||||
1546 | |||||
1547 | static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) { | ||||
1548 | using namespace attr; | ||||
1549 | switch (Rule) { | ||||
1550 | #define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \ | ||||
1551 | case Value: \ | ||||
1552 | return IsAbstract; | ||||
1553 | #include "clang/Basic/AttrSubMatchRulesList.inc" | ||||
1554 | } | ||||
1555 | llvm_unreachable("Invalid attribute subject match rule")::llvm::llvm_unreachable_internal("Invalid attribute subject match rule" , "clang/lib/Parse/ParsePragma.cpp", 1555); | ||||
1556 | return false; | ||||
1557 | } | ||||
1558 | |||||
1559 | static void diagnoseExpectedAttributeSubjectSubRule( | ||||
1560 | Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, | ||||
1561 | SourceLocation SubRuleLoc) { | ||||
1562 | auto Diagnostic = | ||||
1563 | PRef.Diag(SubRuleLoc, | ||||
1564 | diag::err_pragma_attribute_expected_subject_sub_identifier) | ||||
1565 | << PrimaryRuleName; | ||||
1566 | if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) | ||||
1567 | Diagnostic << /*SubRulesSupported=*/1 << SubRules; | ||||
1568 | else | ||||
1569 | Diagnostic << /*SubRulesSupported=*/0; | ||||
1570 | } | ||||
1571 | |||||
1572 | static void diagnoseUnknownAttributeSubjectSubRule( | ||||
1573 | Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, | ||||
1574 | StringRef SubRuleName, SourceLocation SubRuleLoc) { | ||||
1575 | |||||
1576 | auto Diagnostic = | ||||
1577 | PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule) | ||||
1578 | << SubRuleName << PrimaryRuleName; | ||||
1579 | if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) | ||||
1580 | Diagnostic << /*SubRulesSupported=*/1 << SubRules; | ||||
1581 | else | ||||
1582 | Diagnostic << /*SubRulesSupported=*/0; | ||||
1583 | } | ||||
1584 | |||||
1585 | bool Parser::ParsePragmaAttributeSubjectMatchRuleSet( | ||||
1586 | attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc, | ||||
1587 | SourceLocation &LastMatchRuleEndLoc) { | ||||
1588 | bool IsAny = false; | ||||
1589 | BalancedDelimiterTracker AnyParens(*this, tok::l_paren); | ||||
1590 | if (getIdentifier(Tok) == "any") { | ||||
1591 | AnyLoc = ConsumeToken(); | ||||
1592 | IsAny = true; | ||||
1593 | if (AnyParens.expectAndConsume()) | ||||
1594 | return true; | ||||
1595 | } | ||||
1596 | |||||
1597 | do { | ||||
1598 | // Parse the subject matcher rule. | ||||
1599 | StringRef Name = getIdentifier(Tok); | ||||
1600 | if (Name.empty()) { | ||||
1601 | Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier); | ||||
1602 | return true; | ||||
1603 | } | ||||
1604 | std::pair<std::optional<attr::SubjectMatchRule>, | ||||
1605 | std::optional<attr::SubjectMatchRule> (*)(StringRef, bool)> | ||||
1606 | Rule = isAttributeSubjectMatchRule(Name); | ||||
1607 | if (!Rule.first) { | ||||
1608 | Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name; | ||||
1609 | return true; | ||||
1610 | } | ||||
1611 | attr::SubjectMatchRule PrimaryRule = *Rule.first; | ||||
1612 | SourceLocation RuleLoc = ConsumeToken(); | ||||
1613 | |||||
1614 | BalancedDelimiterTracker Parens(*this, tok::l_paren); | ||||
1615 | if (isAbstractAttrMatcherRule(PrimaryRule)) { | ||||
1616 | if (Parens.expectAndConsume()) | ||||
1617 | return true; | ||||
1618 | } else if (Parens.consumeOpen()) { | ||||
1619 | if (!SubjectMatchRules | ||||
1620 | .insert( | ||||
1621 | std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc))) | ||||
1622 | .second) | ||||
1623 | Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) | ||||
1624 | << Name | ||||
1625 | << FixItHint::CreateRemoval(SourceRange( | ||||
1626 | RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc)); | ||||
1627 | LastMatchRuleEndLoc = RuleLoc; | ||||
1628 | continue; | ||||
1629 | } | ||||
1630 | |||||
1631 | // Parse the sub-rules. | ||||
1632 | StringRef SubRuleName = getIdentifier(Tok); | ||||
1633 | if (SubRuleName.empty()) { | ||||
1634 | diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, | ||||
1635 | Tok.getLocation()); | ||||
1636 | return true; | ||||
1637 | } | ||||
1638 | attr::SubjectMatchRule SubRule; | ||||
1639 | if (SubRuleName == "unless") { | ||||
1640 | SourceLocation SubRuleLoc = ConsumeToken(); | ||||
1641 | BalancedDelimiterTracker Parens(*this, tok::l_paren); | ||||
1642 | if (Parens.expectAndConsume()) | ||||
1643 | return true; | ||||
1644 | SubRuleName = getIdentifier(Tok); | ||||
1645 | if (SubRuleName.empty()) { | ||||
1646 | diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, | ||||
1647 | SubRuleLoc); | ||||
1648 | return true; | ||||
1649 | } | ||||
1650 | auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true); | ||||
1651 | if (!SubRuleOrNone) { | ||||
1652 | std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")"; | ||||
1653 | diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, | ||||
1654 | SubRuleUnlessName, SubRuleLoc); | ||||
1655 | return true; | ||||
1656 | } | ||||
1657 | SubRule = *SubRuleOrNone; | ||||
1658 | ConsumeToken(); | ||||
1659 | if (Parens.consumeClose()) | ||||
1660 | return true; | ||||
1661 | } else { | ||||
1662 | auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false); | ||||
1663 | if (!SubRuleOrNone) { | ||||
1664 | diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, | ||||
1665 | SubRuleName, Tok.getLocation()); | ||||
1666 | return true; | ||||
1667 | } | ||||
1668 | SubRule = *SubRuleOrNone; | ||||
1669 | ConsumeToken(); | ||||
1670 | } | ||||
1671 | SourceLocation RuleEndLoc = Tok.getLocation(); | ||||
1672 | LastMatchRuleEndLoc = RuleEndLoc; | ||||
1673 | if (Parens.consumeClose()) | ||||
1674 | return true; | ||||
1675 | if (!SubjectMatchRules | ||||
1676 | .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc))) | ||||
1677 | .second) { | ||||
1678 | Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) | ||||
1679 | << attr::getSubjectMatchRuleSpelling(SubRule) | ||||
1680 | << FixItHint::CreateRemoval(SourceRange( | ||||
1681 | RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc)); | ||||
1682 | continue; | ||||
1683 | } | ||||
1684 | } while (IsAny && TryConsumeToken(tok::comma)); | ||||
1685 | |||||
1686 | if (IsAny) | ||||
1687 | if (AnyParens.consumeClose()) | ||||
1688 | return true; | ||||
1689 | |||||
1690 | return false; | ||||
1691 | } | ||||
1692 | |||||
1693 | namespace { | ||||
1694 | |||||
1695 | /// Describes the stage at which attribute subject rule parsing was interrupted. | ||||
1696 | enum class MissingAttributeSubjectRulesRecoveryPoint { | ||||
1697 | Comma, | ||||
1698 | ApplyTo, | ||||
1699 | Equals, | ||||
1700 | Any, | ||||
1701 | None, | ||||
1702 | }; | ||||
1703 | |||||
1704 | MissingAttributeSubjectRulesRecoveryPoint | ||||
1705 | getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) { | ||||
1706 | if (const auto *II = Tok.getIdentifierInfo()) { | ||||
1707 | if (II->isStr("apply_to")) | ||||
1708 | return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo; | ||||
1709 | if (II->isStr("any")) | ||||
1710 | return MissingAttributeSubjectRulesRecoveryPoint::Any; | ||||
1711 | } | ||||
1712 | if (Tok.is(tok::equal)) | ||||
1713 | return MissingAttributeSubjectRulesRecoveryPoint::Equals; | ||||
1714 | return MissingAttributeSubjectRulesRecoveryPoint::None; | ||||
1715 | } | ||||
1716 | |||||
1717 | /// Creates a diagnostic for the attribute subject rule parsing diagnostic that | ||||
1718 | /// suggests the possible attribute subject rules in a fix-it together with | ||||
1719 | /// any other missing tokens. | ||||
1720 | DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic( | ||||
1721 | unsigned DiagID, ParsedAttributes &Attrs, | ||||
1722 | MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) { | ||||
1723 | SourceLocation Loc = PRef.getEndOfPreviousToken(); | ||||
1724 | if (Loc.isInvalid()) | ||||
1725 | Loc = PRef.getCurToken().getLocation(); | ||||
1726 | auto Diagnostic = PRef.Diag(Loc, DiagID); | ||||
1727 | std::string FixIt; | ||||
1728 | MissingAttributeSubjectRulesRecoveryPoint EndPoint = | ||||
1729 | getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken()); | ||||
1730 | if (Point
| ||||
1731 | FixIt = ", "; | ||||
1732 | if (Point
| ||||
1733 | EndPoint
| ||||
1734 | FixIt += "apply_to"; | ||||
1735 | if (Point
| ||||
1736 | EndPoint
| ||||
1737 | FixIt += " = "; | ||||
1738 | SourceRange FixItRange(Loc); | ||||
1739 | if (EndPoint
| ||||
1740 | // Gather the subject match rules that are supported by the attribute. | ||||
1741 | // Add all the possible rules initially. | ||||
1742 | llvm::BitVector IsMatchRuleAvailable(attr::SubjectMatchRule_Last + 1, true); | ||||
1743 | // Remove the ones that are not supported by any of the attributes. | ||||
1744 | for (const ParsedAttr &Attribute : Attrs) { | ||||
1745 | SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> MatchRules; | ||||
1746 | Attribute.getMatchRules(PRef.getLangOpts(), MatchRules); | ||||
1747 | llvm::BitVector IsSupported(attr::SubjectMatchRule_Last + 1); | ||||
1748 | for (const auto &Rule : MatchRules) { | ||||
1749 | // Ensure that the missing rule is reported in the fix-it only when it's | ||||
1750 | // supported in the current language mode. | ||||
1751 | if (!Rule.second) | ||||
1752 | continue; | ||||
1753 | IsSupported[Rule.first] = true; | ||||
1754 | } | ||||
1755 | IsMatchRuleAvailable &= IsSupported; | ||||
1756 | } | ||||
1757 | if (IsMatchRuleAvailable.count() == 0) { | ||||
1758 | // FIXME: We can emit a "fix-it" with a subject list placeholder when | ||||
1759 | // placeholders will be supported by the fix-its. | ||||
1760 | return Diagnostic; | ||||
1761 | } | ||||
1762 | FixIt += "any("; | ||||
1763 | bool NeedsComma = false; | ||||
1764 | for (unsigned I = 0; I <= attr::SubjectMatchRule_Last; I++) { | ||||
1765 | if (!IsMatchRuleAvailable[I]) | ||||
1766 | continue; | ||||
1767 | if (NeedsComma) | ||||
1768 | FixIt += ", "; | ||||
1769 | else | ||||
1770 | NeedsComma = true; | ||||
1771 | FixIt += attr::getSubjectMatchRuleSpelling( | ||||
1772 | static_cast<attr::SubjectMatchRule>(I)); | ||||
1773 | } | ||||
1774 | FixIt += ")"; | ||||
1775 | // Check if we need to remove the range | ||||
1776 | PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch); | ||||
1777 | FixItRange.setEnd(PRef.getCurToken().getLocation()); | ||||
1778 | } | ||||
1779 | if (FixItRange.getBegin() == FixItRange.getEnd()) | ||||
1780 | Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt); | ||||
1781 | else | ||||
1782 | Diagnostic << FixItHint::CreateReplacement( | ||||
1783 | CharSourceRange::getCharRange(FixItRange), FixIt); | ||||
1784 | return Diagnostic; | ||||
1785 | } | ||||
1786 | |||||
1787 | } // end anonymous namespace | ||||
1788 | |||||
1789 | void Parser::HandlePragmaAttribute() { | ||||
1790 | assert(Tok.is(tok::annot_pragma_attribute) &&(static_cast <bool> (Tok.is(tok::annot_pragma_attribute ) && "Expected #pragma attribute annotation token") ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_attribute) && \"Expected #pragma attribute annotation token\"" , "clang/lib/Parse/ParsePragma.cpp", 1791, __extension__ __PRETTY_FUNCTION__ )) | ||||
| |||||
1791 | "Expected #pragma attribute annotation token")(static_cast <bool> (Tok.is(tok::annot_pragma_attribute ) && "Expected #pragma attribute annotation token") ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_attribute) && \"Expected #pragma attribute annotation token\"" , "clang/lib/Parse/ParsePragma.cpp", 1791, __extension__ __PRETTY_FUNCTION__ )); | ||||
1792 | SourceLocation PragmaLoc = Tok.getLocation(); | ||||
1793 | auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue()); | ||||
1794 | if (Info->Action == PragmaAttributeInfo::Pop) { | ||||
1795 | ConsumeAnnotationToken(); | ||||
1796 | Actions.ActOnPragmaAttributePop(PragmaLoc, Info->Namespace); | ||||
1797 | return; | ||||
1798 | } | ||||
1799 | // Parse the actual attribute with its arguments. | ||||
1800 | assert((Info->Action == PragmaAttributeInfo::Push ||(static_cast <bool> ((Info->Action == PragmaAttributeInfo ::Push || Info->Action == PragmaAttributeInfo::Attribute) && "Unexpected #pragma attribute command") ? void (0) : __assert_fail ("(Info->Action == PragmaAttributeInfo::Push || Info->Action == PragmaAttributeInfo::Attribute) && \"Unexpected #pragma attribute command\"" , "clang/lib/Parse/ParsePragma.cpp", 1802, __extension__ __PRETTY_FUNCTION__ )) | ||||
1801 | Info->Action == PragmaAttributeInfo::Attribute) &&(static_cast <bool> ((Info->Action == PragmaAttributeInfo ::Push || Info->Action == PragmaAttributeInfo::Attribute) && "Unexpected #pragma attribute command") ? void (0) : __assert_fail ("(Info->Action == PragmaAttributeInfo::Push || Info->Action == PragmaAttributeInfo::Attribute) && \"Unexpected #pragma attribute command\"" , "clang/lib/Parse/ParsePragma.cpp", 1802, __extension__ __PRETTY_FUNCTION__ )) | ||||
1802 | "Unexpected #pragma attribute command")(static_cast <bool> ((Info->Action == PragmaAttributeInfo ::Push || Info->Action == PragmaAttributeInfo::Attribute) && "Unexpected #pragma attribute command") ? void (0) : __assert_fail ("(Info->Action == PragmaAttributeInfo::Push || Info->Action == PragmaAttributeInfo::Attribute) && \"Unexpected #pragma attribute command\"" , "clang/lib/Parse/ParsePragma.cpp", 1802, __extension__ __PRETTY_FUNCTION__ )); | ||||
1803 | |||||
1804 | if (Info->Action
| ||||
1805 | ConsumeAnnotationToken(); | ||||
1806 | Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Info->Namespace); | ||||
1807 | return; | ||||
1808 | } | ||||
1809 | |||||
1810 | PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false, | ||||
1811 | /*IsReinject=*/false); | ||||
1812 | ConsumeAnnotationToken(); | ||||
1813 | |||||
1814 | ParsedAttributes &Attrs = Info->Attributes; | ||||
1815 | Attrs.clearListOnly(); | ||||
1816 | |||||
1817 | auto SkipToEnd = [this]() { | ||||
1818 | SkipUntil(tok::eof, StopBeforeMatch); | ||||
1819 | ConsumeToken(); | ||||
1820 | }; | ||||
1821 | |||||
1822 | if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { | ||||
1823 | // Parse the CXX11 style attribute. | ||||
1824 | ParseCXX11AttributeSpecifier(Attrs); | ||||
1825 | } else if (Tok.is(tok::kw___attribute)) { | ||||
1826 | ConsumeToken(); | ||||
1827 | if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, | ||||
1828 | "attribute")) | ||||
1829 | return SkipToEnd(); | ||||
1830 | if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) | ||||
1831 | return SkipToEnd(); | ||||
1832 | |||||
1833 | // FIXME: The practical usefulness of completion here is limited because | ||||
1834 | // we only get here if the line has balanced parens. | ||||
1835 | if (Tok.is(tok::code_completion)) { | ||||
1836 | cutOffParsing(); | ||||
1837 | // FIXME: suppress completion of unsupported attributes? | ||||
1838 | Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU); | ||||
1839 | return SkipToEnd(); | ||||
1840 | } | ||||
1841 | |||||
1842 | // Parse the comma-separated list of attributes. | ||||
1843 | do { | ||||
1844 | if (Tok.isNot(tok::identifier)) { | ||||
1845 | Diag(Tok, diag::err_pragma_attribute_expected_attribute_name); | ||||
1846 | SkipToEnd(); | ||||
1847 | return; | ||||
1848 | } | ||||
1849 | IdentifierInfo *AttrName = Tok.getIdentifierInfo(); | ||||
1850 | SourceLocation AttrNameLoc = ConsumeToken(); | ||||
1851 | |||||
1852 | if (Tok.isNot(tok::l_paren)) | ||||
1853 | Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, | ||||
1854 | ParsedAttr::Form::GNU()); | ||||
1855 | else | ||||
1856 | ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr, | ||||
1857 | /*ScopeName=*/nullptr, | ||||
1858 | /*ScopeLoc=*/SourceLocation(), | ||||
1859 | ParsedAttr::Form::GNU(), | ||||
1860 | /*Declarator=*/nullptr); | ||||
1861 | } while (TryConsumeToken(tok::comma)); | ||||
1862 | |||||
1863 | if (ExpectAndConsume(tok::r_paren)) | ||||
1864 | return SkipToEnd(); | ||||
1865 | if (ExpectAndConsume(tok::r_paren)) | ||||
1866 | return SkipToEnd(); | ||||
1867 | } else if (Tok.is(tok::kw___declspec)) { | ||||
1868 | ParseMicrosoftDeclSpecs(Attrs); | ||||
1869 | } else { | ||||
1870 | Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax); | ||||
1871 | if (Tok.getIdentifierInfo()) { | ||||
1872 | // If we suspect that this is an attribute suggest the use of | ||||
1873 | // '__attribute__'. | ||||
1874 | if (ParsedAttr::getParsedKind( | ||||
1875 | Tok.getIdentifierInfo(), /*ScopeName=*/nullptr, | ||||
1876 | ParsedAttr::AS_GNU) != ParsedAttr::UnknownAttribute) { | ||||
1877 | SourceLocation InsertStartLoc = Tok.getLocation(); | ||||
1878 | ConsumeToken(); | ||||
1879 | if (Tok.is(tok::l_paren)) { | ||||
1880 | ConsumeAnyToken(); | ||||
1881 | SkipUntil(tok::r_paren, StopBeforeMatch); | ||||
1882 | if (Tok.isNot(tok::r_paren)) | ||||
1883 | return SkipToEnd(); | ||||
1884 | } | ||||
1885 | Diag(Tok, diag::note_pragma_attribute_use_attribute_kw) | ||||
1886 | << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((") | ||||
1887 | << FixItHint::CreateInsertion(Tok.getEndLoc(), "))"); | ||||
1888 | } | ||||
1889 | } | ||||
1890 | SkipToEnd(); | ||||
1891 | return; | ||||
1892 | } | ||||
1893 | |||||
1894 | if (Attrs.empty() || Attrs.begin()->isInvalid()) { | ||||
1895 | SkipToEnd(); | ||||
1896 | return; | ||||
1897 | } | ||||
1898 | |||||
1899 | for (const ParsedAttr &Attribute : Attrs) { | ||||
1900 | if (!Attribute.isSupportedByPragmaAttribute()) { | ||||
1901 | Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute) | ||||
1902 | << Attribute; | ||||
1903 | SkipToEnd(); | ||||
1904 | return; | ||||
1905 | } | ||||
1906 | } | ||||
1907 | |||||
1908 | // Parse the subject-list. | ||||
1909 | if (!TryConsumeToken(tok::comma)) { | ||||
1910 | createExpectedAttributeSubjectRulesTokenDiagnostic( | ||||
1911 | diag::err_expected, Attrs, | ||||
1912 | MissingAttributeSubjectRulesRecoveryPoint::Comma, *this) | ||||
1913 | << tok::comma; | ||||
1914 | SkipToEnd(); | ||||
1915 | return; | ||||
1916 | } | ||||
1917 | |||||
1918 | if (Tok.isNot(tok::identifier)) { | ||||
1919 | createExpectedAttributeSubjectRulesTokenDiagnostic( | ||||
1920 | diag::err_pragma_attribute_invalid_subject_set_specifier, Attrs, | ||||
1921 | MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); | ||||
1922 | SkipToEnd(); | ||||
1923 | return; | ||||
1924 | } | ||||
1925 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
1926 | if (!II->isStr("apply_to")) { | ||||
1927 | createExpectedAttributeSubjectRulesTokenDiagnostic( | ||||
1928 | diag::err_pragma_attribute_invalid_subject_set_specifier, Attrs, | ||||
1929 | MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); | ||||
1930 | SkipToEnd(); | ||||
1931 | return; | ||||
1932 | } | ||||
1933 | ConsumeToken(); | ||||
1934 | |||||
1935 | if (!TryConsumeToken(tok::equal)) { | ||||
1936 | createExpectedAttributeSubjectRulesTokenDiagnostic( | ||||
1937 | diag::err_expected, Attrs, | ||||
1938 | MissingAttributeSubjectRulesRecoveryPoint::Equals, *this) | ||||
1939 | << tok::equal; | ||||
1940 | SkipToEnd(); | ||||
1941 | return; | ||||
1942 | } | ||||
1943 | |||||
1944 | attr::ParsedSubjectMatchRuleSet SubjectMatchRules; | ||||
1945 | SourceLocation AnyLoc, LastMatchRuleEndLoc; | ||||
1946 | if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc, | ||||
1947 | LastMatchRuleEndLoc)) { | ||||
1948 | SkipToEnd(); | ||||
1949 | return; | ||||
1950 | } | ||||
1951 | |||||
1952 | // Tokens following an ill-formed attribute will remain in the token stream | ||||
1953 | // and must be removed. | ||||
1954 | if (Tok.isNot(tok::eof)) { | ||||
1955 | Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute); | ||||
1956 | SkipToEnd(); | ||||
1957 | return; | ||||
1958 | } | ||||
1959 | |||||
1960 | // Consume the eof terminator token. | ||||
1961 | ConsumeToken(); | ||||
1962 | |||||
1963 | // Handle a mixed push/attribute by desurging to a push, then an attribute. | ||||
1964 | if (Info->Action == PragmaAttributeInfo::Push) | ||||
1965 | Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Info->Namespace); | ||||
1966 | |||||
1967 | for (ParsedAttr &Attribute : Attrs) { | ||||
1968 | Actions.ActOnPragmaAttributeAttribute(Attribute, PragmaLoc, | ||||
1969 | SubjectMatchRules); | ||||
1970 | } | ||||
1971 | } | ||||
1972 | |||||
1973 | // #pragma GCC visibility comes in two variants: | ||||
1974 | // 'push' '(' [visibility] ')' | ||||
1975 | // 'pop' | ||||
1976 | void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, | ||||
1977 | PragmaIntroducer Introducer, | ||||
1978 | Token &VisTok) { | ||||
1979 | SourceLocation VisLoc = VisTok.getLocation(); | ||||
1980 | |||||
1981 | Token Tok; | ||||
1982 | PP.LexUnexpandedToken(Tok); | ||||
1983 | |||||
1984 | const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); | ||||
1985 | |||||
1986 | const IdentifierInfo *VisType; | ||||
1987 | if (PushPop && PushPop->isStr("pop")) { | ||||
1988 | VisType = nullptr; | ||||
1989 | } else if (PushPop && PushPop->isStr("push")) { | ||||
1990 | PP.LexUnexpandedToken(Tok); | ||||
1991 | if (Tok.isNot(tok::l_paren)) { | ||||
1992 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) | ||||
1993 | << "visibility"; | ||||
1994 | return; | ||||
1995 | } | ||||
1996 | PP.LexUnexpandedToken(Tok); | ||||
1997 | VisType = Tok.getIdentifierInfo(); | ||||
1998 | if (!VisType) { | ||||
1999 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2000 | << "visibility"; | ||||
2001 | return; | ||||
2002 | } | ||||
2003 | PP.LexUnexpandedToken(Tok); | ||||
2004 | if (Tok.isNot(tok::r_paren)) { | ||||
2005 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | ||||
2006 | << "visibility"; | ||||
2007 | return; | ||||
2008 | } | ||||
2009 | } else { | ||||
2010 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2011 | << "visibility"; | ||||
2012 | return; | ||||
2013 | } | ||||
2014 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2015 | PP.LexUnexpandedToken(Tok); | ||||
2016 | if (Tok.isNot(tok::eod)) { | ||||
2017 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2018 | << "visibility"; | ||||
2019 | return; | ||||
2020 | } | ||||
2021 | |||||
2022 | auto Toks = std::make_unique<Token[]>(1); | ||||
2023 | Toks[0].startToken(); | ||||
2024 | Toks[0].setKind(tok::annot_pragma_vis); | ||||
2025 | Toks[0].setLocation(VisLoc); | ||||
2026 | Toks[0].setAnnotationEndLoc(EndLoc); | ||||
2027 | Toks[0].setAnnotationValue( | ||||
2028 | const_cast<void *>(static_cast<const void *>(VisType))); | ||||
2029 | PP.EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion=*/true, | ||||
2030 | /*IsReinject=*/false); | ||||
2031 | } | ||||
2032 | |||||
2033 | // #pragma pack(...) comes in the following delicious flavors: | ||||
2034 | // pack '(' [integer] ')' | ||||
2035 | // pack '(' 'show' ')' | ||||
2036 | // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' | ||||
2037 | void PragmaPackHandler::HandlePragma(Preprocessor &PP, | ||||
2038 | PragmaIntroducer Introducer, | ||||
2039 | Token &PackTok) { | ||||
2040 | SourceLocation PackLoc = PackTok.getLocation(); | ||||
2041 | |||||
2042 | Token Tok; | ||||
2043 | PP.Lex(Tok); | ||||
2044 | if (Tok.isNot(tok::l_paren)) { | ||||
2045 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack"; | ||||
2046 | return; | ||||
2047 | } | ||||
2048 | |||||
2049 | Sema::PragmaMsStackAction Action = Sema::PSK_Reset; | ||||
2050 | StringRef SlotLabel; | ||||
2051 | Token Alignment; | ||||
2052 | Alignment.startToken(); | ||||
2053 | PP.Lex(Tok); | ||||
2054 | if (Tok.is(tok::numeric_constant)) { | ||||
2055 | Alignment = Tok; | ||||
2056 | |||||
2057 | PP.Lex(Tok); | ||||
2058 | |||||
2059 | // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting | ||||
2060 | // the push/pop stack. | ||||
2061 | // In Apple gcc/XL, #pragma pack(4) is equivalent to #pragma pack(push, 4) | ||||
2062 | Action = (PP.getLangOpts().ApplePragmaPack || PP.getLangOpts().XLPragmaPack) | ||||
2063 | ? Sema::PSK_Push_Set | ||||
2064 | : Sema::PSK_Set; | ||||
2065 | } else if (Tok.is(tok::identifier)) { | ||||
2066 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2067 | if (II->isStr("show")) { | ||||
2068 | Action = Sema::PSK_Show; | ||||
2069 | PP.Lex(Tok); | ||||
2070 | } else { | ||||
2071 | if (II->isStr("push")) { | ||||
2072 | Action = Sema::PSK_Push; | ||||
2073 | } else if (II->isStr("pop")) { | ||||
2074 | Action = Sema::PSK_Pop; | ||||
2075 | } else { | ||||
2076 | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack"; | ||||
2077 | return; | ||||
2078 | } | ||||
2079 | PP.Lex(Tok); | ||||
2080 | |||||
2081 | if (Tok.is(tok::comma)) { | ||||
2082 | PP.Lex(Tok); | ||||
2083 | |||||
2084 | if (Tok.is(tok::numeric_constant)) { | ||||
2085 | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | ||||
2086 | Alignment = Tok; | ||||
2087 | |||||
2088 | PP.Lex(Tok); | ||||
2089 | } else if (Tok.is(tok::identifier)) { | ||||
2090 | SlotLabel = Tok.getIdentifierInfo()->getName(); | ||||
2091 | PP.Lex(Tok); | ||||
2092 | |||||
2093 | if (Tok.is(tok::comma)) { | ||||
2094 | PP.Lex(Tok); | ||||
2095 | |||||
2096 | if (Tok.isNot(tok::numeric_constant)) { | ||||
2097 | PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); | ||||
2098 | return; | ||||
2099 | } | ||||
2100 | |||||
2101 | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | ||||
2102 | Alignment = Tok; | ||||
2103 | |||||
2104 | PP.Lex(Tok); | ||||
2105 | } | ||||
2106 | } else { | ||||
2107 | PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); | ||||
2108 | return; | ||||
2109 | } | ||||
2110 | } | ||||
2111 | } | ||||
2112 | } else if (PP.getLangOpts().ApplePragmaPack || | ||||
2113 | PP.getLangOpts().XLPragmaPack) { | ||||
2114 | // In MSVC/gcc, #pragma pack() resets the alignment without affecting | ||||
2115 | // the push/pop stack. | ||||
2116 | // In Apple gcc and IBM XL, #pragma pack() is equivalent to #pragma | ||||
2117 | // pack(pop). | ||||
2118 | Action = Sema::PSK_Pop; | ||||
2119 | } | ||||
2120 | |||||
2121 | if (Tok.isNot(tok::r_paren)) { | ||||
2122 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack"; | ||||
2123 | return; | ||||
2124 | } | ||||
2125 | |||||
2126 | SourceLocation RParenLoc = Tok.getLocation(); | ||||
2127 | PP.Lex(Tok); | ||||
2128 | if (Tok.isNot(tok::eod)) { | ||||
2129 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; | ||||
2130 | return; | ||||
2131 | } | ||||
2132 | |||||
2133 | Sema::PragmaPackInfo *Info = | ||||
2134 | PP.getPreprocessorAllocator().Allocate<Sema::PragmaPackInfo>(1); | ||||
2135 | Info->Action = Action; | ||||
2136 | Info->SlotLabel = SlotLabel; | ||||
2137 | Info->Alignment = Alignment; | ||||
2138 | |||||
2139 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
2140 | 1); | ||||
2141 | Toks[0].startToken(); | ||||
2142 | Toks[0].setKind(tok::annot_pragma_pack); | ||||
2143 | Toks[0].setLocation(PackLoc); | ||||
2144 | Toks[0].setAnnotationEndLoc(RParenLoc); | ||||
2145 | Toks[0].setAnnotationValue(static_cast<void*>(Info)); | ||||
2146 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2147 | /*IsReinject=*/false); | ||||
2148 | } | ||||
2149 | |||||
2150 | // #pragma ms_struct on | ||||
2151 | // #pragma ms_struct off | ||||
2152 | void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, | ||||
2153 | PragmaIntroducer Introducer, | ||||
2154 | Token &MSStructTok) { | ||||
2155 | PragmaMSStructKind Kind = PMSST_OFF; | ||||
2156 | |||||
2157 | Token Tok; | ||||
2158 | PP.Lex(Tok); | ||||
2159 | if (Tok.isNot(tok::identifier)) { | ||||
2160 | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); | ||||
2161 | return; | ||||
2162 | } | ||||
2163 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2164 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2165 | if (II->isStr("on")) { | ||||
2166 | Kind = PMSST_ON; | ||||
2167 | PP.Lex(Tok); | ||||
2168 | } | ||||
2169 | else if (II->isStr("off") || II->isStr("reset")) | ||||
2170 | PP.Lex(Tok); | ||||
2171 | else { | ||||
2172 | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); | ||||
2173 | return; | ||||
2174 | } | ||||
2175 | |||||
2176 | if (Tok.isNot(tok::eod)) { | ||||
2177 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2178 | << "ms_struct"; | ||||
2179 | return; | ||||
2180 | } | ||||
2181 | |||||
2182 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
2183 | 1); | ||||
2184 | Toks[0].startToken(); | ||||
2185 | Toks[0].setKind(tok::annot_pragma_msstruct); | ||||
2186 | Toks[0].setLocation(MSStructTok.getLocation()); | ||||
2187 | Toks[0].setAnnotationEndLoc(EndLoc); | ||||
2188 | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | ||||
2189 | static_cast<uintptr_t>(Kind))); | ||||
2190 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2191 | /*IsReinject=*/false); | ||||
2192 | } | ||||
2193 | |||||
2194 | // #pragma clang section bss="abc" data="" rodata="def" text="" relro="" | ||||
2195 | void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, | ||||
2196 | PragmaIntroducer Introducer, | ||||
2197 | Token &FirstToken) { | ||||
2198 | |||||
2199 | Token Tok; | ||||
2200 | auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid; | ||||
2201 | |||||
2202 | PP.Lex(Tok); // eat 'section' | ||||
2203 | while (Tok.isNot(tok::eod)) { | ||||
2204 | if (Tok.isNot(tok::identifier)) { | ||||
2205 | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; | ||||
2206 | return; | ||||
2207 | } | ||||
2208 | |||||
2209 | const IdentifierInfo *SecType = Tok.getIdentifierInfo(); | ||||
2210 | if (SecType->isStr("bss")) | ||||
2211 | SecKind = Sema::PragmaClangSectionKind::PCSK_BSS; | ||||
2212 | else if (SecType->isStr("data")) | ||||
2213 | SecKind = Sema::PragmaClangSectionKind::PCSK_Data; | ||||
2214 | else if (SecType->isStr("rodata")) | ||||
2215 | SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata; | ||||
2216 | else if (SecType->isStr("relro")) | ||||
2217 | SecKind = Sema::PragmaClangSectionKind::PCSK_Relro; | ||||
2218 | else if (SecType->isStr("text")) | ||||
2219 | SecKind = Sema::PragmaClangSectionKind::PCSK_Text; | ||||
2220 | else { | ||||
2221 | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; | ||||
2222 | return; | ||||
2223 | } | ||||
2224 | |||||
2225 | SourceLocation PragmaLocation = Tok.getLocation(); | ||||
2226 | PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text'] | ||||
2227 | if (Tok.isNot(tok::equal)) { | ||||
2228 | PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind; | ||||
2229 | return; | ||||
2230 | } | ||||
2231 | |||||
2232 | std::string SecName; | ||||
2233 | if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false)) | ||||
2234 | return; | ||||
2235 | |||||
2236 | Actions.ActOnPragmaClangSection( | ||||
2237 | PragmaLocation, | ||||
2238 | (SecName.size() ? Sema::PragmaClangSectionAction::PCSA_Set | ||||
2239 | : Sema::PragmaClangSectionAction::PCSA_Clear), | ||||
2240 | SecKind, SecName); | ||||
2241 | } | ||||
2242 | } | ||||
2243 | |||||
2244 | // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} | ||||
2245 | // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} | ||||
2246 | // #pragma 'align' '(' {'native','natural','mac68k','power','reset'} ')' | ||||
2247 | static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, | ||||
2248 | bool IsOptions) { | ||||
2249 | Token Tok; | ||||
2250 | |||||
2251 | if (IsOptions) { | ||||
2252 | PP.Lex(Tok); | ||||
2253 | if (Tok.isNot(tok::identifier) || | ||||
2254 | !Tok.getIdentifierInfo()->isStr("align")) { | ||||
2255 | PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); | ||||
2256 | return; | ||||
2257 | } | ||||
2258 | } | ||||
2259 | |||||
2260 | PP.Lex(Tok); | ||||
2261 | if (PP.getLangOpts().XLPragmaPack) { | ||||
2262 | if (Tok.isNot(tok::l_paren)) { | ||||
2263 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "align"; | ||||
2264 | return; | ||||
2265 | } | ||||
2266 | } else if (Tok.isNot(tok::equal)) { | ||||
2267 | PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal) | ||||
2268 | << IsOptions; | ||||
2269 | return; | ||||
2270 | } | ||||
2271 | |||||
2272 | PP.Lex(Tok); | ||||
2273 | if (Tok.isNot(tok::identifier)) { | ||||
2274 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2275 | << (IsOptions ? "options" : "align"); | ||||
2276 | return; | ||||
2277 | } | ||||
2278 | |||||
2279 | Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural; | ||||
2280 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2281 | if (II->isStr("native")) | ||||
2282 | Kind = Sema::POAK_Native; | ||||
2283 | else if (II->isStr("natural")) | ||||
2284 | Kind = Sema::POAK_Natural; | ||||
2285 | else if (II->isStr("packed")) | ||||
2286 | Kind = Sema::POAK_Packed; | ||||
2287 | else if (II->isStr("power")) | ||||
2288 | Kind = Sema::POAK_Power; | ||||
2289 | else if (II->isStr("mac68k")) | ||||
2290 | Kind = Sema::POAK_Mac68k; | ||||
2291 | else if (II->isStr("reset")) | ||||
2292 | Kind = Sema::POAK_Reset; | ||||
2293 | else { | ||||
2294 | PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option) | ||||
2295 | << IsOptions; | ||||
2296 | return; | ||||
2297 | } | ||||
2298 | |||||
2299 | if (PP.getLangOpts().XLPragmaPack) { | ||||
2300 | PP.Lex(Tok); | ||||
2301 | if (Tok.isNot(tok::r_paren)) { | ||||
2302 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "align"; | ||||
2303 | return; | ||||
2304 | } | ||||
2305 | } | ||||
2306 | |||||
2307 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2308 | PP.Lex(Tok); | ||||
2309 | if (Tok.isNot(tok::eod)) { | ||||
2310 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2311 | << (IsOptions ? "options" : "align"); | ||||
2312 | return; | ||||
2313 | } | ||||
2314 | |||||
2315 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
2316 | 1); | ||||
2317 | Toks[0].startToken(); | ||||
2318 | Toks[0].setKind(tok::annot_pragma_align); | ||||
2319 | Toks[0].setLocation(FirstTok.getLocation()); | ||||
2320 | Toks[0].setAnnotationEndLoc(EndLoc); | ||||
2321 | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | ||||
2322 | static_cast<uintptr_t>(Kind))); | ||||
2323 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2324 | /*IsReinject=*/false); | ||||
2325 | } | ||||
2326 | |||||
2327 | void PragmaAlignHandler::HandlePragma(Preprocessor &PP, | ||||
2328 | PragmaIntroducer Introducer, | ||||
2329 | Token &AlignTok) { | ||||
2330 | ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false); | ||||
2331 | } | ||||
2332 | |||||
2333 | void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, | ||||
2334 | PragmaIntroducer Introducer, | ||||
2335 | Token &OptionsTok) { | ||||
2336 | ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true); | ||||
2337 | } | ||||
2338 | |||||
2339 | // #pragma unused(identifier) | ||||
2340 | void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, | ||||
2341 | PragmaIntroducer Introducer, | ||||
2342 | Token &UnusedTok) { | ||||
2343 | // FIXME: Should we be expanding macros here? My guess is no. | ||||
2344 | SourceLocation UnusedLoc = UnusedTok.getLocation(); | ||||
2345 | |||||
2346 | // Lex the left '('. | ||||
2347 | Token Tok; | ||||
2348 | PP.Lex(Tok); | ||||
2349 | if (Tok.isNot(tok::l_paren)) { | ||||
2350 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused"; | ||||
2351 | return; | ||||
2352 | } | ||||
2353 | |||||
2354 | // Lex the declaration reference(s). | ||||
2355 | SmallVector<Token, 5> Identifiers; | ||||
2356 | SourceLocation RParenLoc; | ||||
2357 | bool LexID = true; | ||||
2358 | |||||
2359 | while (true) { | ||||
2360 | PP.Lex(Tok); | ||||
2361 | |||||
2362 | if (LexID) { | ||||
2363 | if (Tok.is(tok::identifier)) { | ||||
2364 | Identifiers.push_back(Tok); | ||||
2365 | LexID = false; | ||||
2366 | continue; | ||||
2367 | } | ||||
2368 | |||||
2369 | // Illegal token! | ||||
2370 | PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var); | ||||
2371 | return; | ||||
2372 | } | ||||
2373 | |||||
2374 | // We are execting a ')' or a ','. | ||||
2375 | if (Tok.is(tok::comma)) { | ||||
2376 | LexID = true; | ||||
2377 | continue; | ||||
2378 | } | ||||
2379 | |||||
2380 | if (Tok.is(tok::r_paren)) { | ||||
2381 | RParenLoc = Tok.getLocation(); | ||||
2382 | break; | ||||
2383 | } | ||||
2384 | |||||
2385 | // Illegal token! | ||||
2386 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << "unused"; | ||||
2387 | return; | ||||
2388 | } | ||||
2389 | |||||
2390 | PP.Lex(Tok); | ||||
2391 | if (Tok.isNot(tok::eod)) { | ||||
2392 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | ||||
2393 | "unused"; | ||||
2394 | return; | ||||
2395 | } | ||||
2396 | |||||
2397 | // Verify that we have a location for the right parenthesis. | ||||
2398 | assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'")(static_cast <bool> (RParenLoc.isValid() && "Valid '#pragma unused' must have ')'" ) ? void (0) : __assert_fail ("RParenLoc.isValid() && \"Valid '#pragma unused' must have ')'\"" , "clang/lib/Parse/ParsePragma.cpp", 2398, __extension__ __PRETTY_FUNCTION__ )); | ||||
2399 | assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments")(static_cast <bool> (!Identifiers.empty() && "Valid '#pragma unused' must have arguments" ) ? void (0) : __assert_fail ("!Identifiers.empty() && \"Valid '#pragma unused' must have arguments\"" , "clang/lib/Parse/ParsePragma.cpp", 2399, __extension__ __PRETTY_FUNCTION__ )); | ||||
2400 | |||||
2401 | // For each identifier token, insert into the token stream a | ||||
2402 | // annot_pragma_unused token followed by the identifier token. | ||||
2403 | // This allows us to cache a "#pragma unused" that occurs inside an inline | ||||
2404 | // C++ member function. | ||||
2405 | |||||
2406 | MutableArrayRef<Token> Toks( | ||||
2407 | PP.getPreprocessorAllocator().Allocate<Token>(2 * Identifiers.size()), | ||||
2408 | 2 * Identifiers.size()); | ||||
2409 | for (unsigned i=0; i != Identifiers.size(); i++) { | ||||
2410 | Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; | ||||
2411 | pragmaUnusedTok.startToken(); | ||||
2412 | pragmaUnusedTok.setKind(tok::annot_pragma_unused); | ||||
2413 | pragmaUnusedTok.setLocation(UnusedLoc); | ||||
2414 | idTok = Identifiers[i]; | ||||
2415 | } | ||||
2416 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2417 | /*IsReinject=*/false); | ||||
2418 | } | ||||
2419 | |||||
2420 | // #pragma weak identifier | ||||
2421 | // #pragma weak identifier '=' identifier | ||||
2422 | void PragmaWeakHandler::HandlePragma(Preprocessor &PP, | ||||
2423 | PragmaIntroducer Introducer, | ||||
2424 | Token &WeakTok) { | ||||
2425 | SourceLocation WeakLoc = WeakTok.getLocation(); | ||||
2426 | |||||
2427 | Token Tok; | ||||
2428 | PP.Lex(Tok); | ||||
2429 | if (Tok.isNot(tok::identifier)) { | ||||
2430 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; | ||||
2431 | return; | ||||
2432 | } | ||||
2433 | |||||
2434 | Token WeakName = Tok; | ||||
2435 | bool HasAlias = false; | ||||
2436 | Token AliasName; | ||||
2437 | |||||
2438 | PP.Lex(Tok); | ||||
2439 | if (Tok.is(tok::equal)) { | ||||
2440 | HasAlias = true; | ||||
2441 | PP.Lex(Tok); | ||||
2442 | if (Tok.isNot(tok::identifier)) { | ||||
2443 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2444 | << "weak"; | ||||
2445 | return; | ||||
2446 | } | ||||
2447 | AliasName = Tok; | ||||
2448 | PP.Lex(Tok); | ||||
2449 | } | ||||
2450 | |||||
2451 | if (Tok.isNot(tok::eod)) { | ||||
2452 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; | ||||
2453 | return; | ||||
2454 | } | ||||
2455 | |||||
2456 | if (HasAlias) { | ||||
2457 | MutableArrayRef<Token> Toks( | ||||
2458 | PP.getPreprocessorAllocator().Allocate<Token>(3), 3); | ||||
2459 | Token &pragmaUnusedTok = Toks[0]; | ||||
2460 | pragmaUnusedTok.startToken(); | ||||
2461 | pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); | ||||
2462 | pragmaUnusedTok.setLocation(WeakLoc); | ||||
2463 | pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation()); | ||||
2464 | Toks[1] = WeakName; | ||||
2465 | Toks[2] = AliasName; | ||||
2466 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2467 | /*IsReinject=*/false); | ||||
2468 | } else { | ||||
2469 | MutableArrayRef<Token> Toks( | ||||
2470 | PP.getPreprocessorAllocator().Allocate<Token>(2), 2); | ||||
2471 | Token &pragmaUnusedTok = Toks[0]; | ||||
2472 | pragmaUnusedTok.startToken(); | ||||
2473 | pragmaUnusedTok.setKind(tok::annot_pragma_weak); | ||||
2474 | pragmaUnusedTok.setLocation(WeakLoc); | ||||
2475 | pragmaUnusedTok.setAnnotationEndLoc(WeakLoc); | ||||
2476 | Toks[1] = WeakName; | ||||
2477 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2478 | /*IsReinject=*/false); | ||||
2479 | } | ||||
2480 | } | ||||
2481 | |||||
2482 | // #pragma redefine_extname identifier identifier | ||||
2483 | void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, | ||||
2484 | PragmaIntroducer Introducer, | ||||
2485 | Token &RedefToken) { | ||||
2486 | SourceLocation RedefLoc = RedefToken.getLocation(); | ||||
2487 | |||||
2488 | Token Tok; | ||||
2489 | PP.Lex(Tok); | ||||
2490 | if (Tok.isNot(tok::identifier)) { | ||||
2491 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << | ||||
2492 | "redefine_extname"; | ||||
2493 | return; | ||||
2494 | } | ||||
2495 | |||||
2496 | Token RedefName = Tok; | ||||
2497 | PP.Lex(Tok); | ||||
2498 | |||||
2499 | if (Tok.isNot(tok::identifier)) { | ||||
2500 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2501 | << "redefine_extname"; | ||||
2502 | return; | ||||
2503 | } | ||||
2504 | |||||
2505 | Token AliasName = Tok; | ||||
2506 | PP.Lex(Tok); | ||||
2507 | |||||
2508 | if (Tok.isNot(tok::eod)) { | ||||
2509 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | ||||
2510 | "redefine_extname"; | ||||
2511 | return; | ||||
2512 | } | ||||
2513 | |||||
2514 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(3), | ||||
2515 | 3); | ||||
2516 | Token &pragmaRedefTok = Toks[0]; | ||||
2517 | pragmaRedefTok.startToken(); | ||||
2518 | pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); | ||||
2519 | pragmaRedefTok.setLocation(RedefLoc); | ||||
2520 | pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation()); | ||||
2521 | Toks[1] = RedefName; | ||||
2522 | Toks[2] = AliasName; | ||||
2523 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2524 | /*IsReinject=*/false); | ||||
2525 | } | ||||
2526 | |||||
2527 | void PragmaFPContractHandler::HandlePragma(Preprocessor &PP, | ||||
2528 | PragmaIntroducer Introducer, | ||||
2529 | Token &Tok) { | ||||
2530 | tok::OnOffSwitch OOS; | ||||
2531 | if (PP.LexOnOffSwitch(OOS)) | ||||
2532 | return; | ||||
2533 | |||||
2534 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
2535 | 1); | ||||
2536 | Toks[0].startToken(); | ||||
2537 | Toks[0].setKind(tok::annot_pragma_fp_contract); | ||||
2538 | Toks[0].setLocation(Tok.getLocation()); | ||||
2539 | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | ||||
2540 | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | ||||
2541 | static_cast<uintptr_t>(OOS))); | ||||
2542 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2543 | /*IsReinject=*/false); | ||||
2544 | } | ||||
2545 | |||||
2546 | void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, | ||||
2547 | PragmaIntroducer Introducer, | ||||
2548 | Token &Tok) { | ||||
2549 | PP.LexUnexpandedToken(Tok); | ||||
2550 | if (Tok.isNot(tok::identifier)) { | ||||
2551 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << | ||||
2552 | "OPENCL"; | ||||
2553 | return; | ||||
2554 | } | ||||
2555 | IdentifierInfo *Ext = Tok.getIdentifierInfo(); | ||||
2556 | SourceLocation NameLoc = Tok.getLocation(); | ||||
2557 | |||||
2558 | PP.Lex(Tok); | ||||
2559 | if (Tok.isNot(tok::colon)) { | ||||
2560 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << Ext; | ||||
2561 | return; | ||||
2562 | } | ||||
2563 | |||||
2564 | PP.Lex(Tok); | ||||
2565 | if (Tok.isNot(tok::identifier)) { | ||||
2566 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) << 0; | ||||
2567 | return; | ||||
2568 | } | ||||
2569 | IdentifierInfo *Pred = Tok.getIdentifierInfo(); | ||||
2570 | |||||
2571 | OpenCLExtState State; | ||||
2572 | if (Pred->isStr("enable")) { | ||||
2573 | State = Enable; | ||||
2574 | } else if (Pred->isStr("disable")) { | ||||
2575 | State = Disable; | ||||
2576 | } else if (Pred->isStr("begin")) | ||||
2577 | State = Begin; | ||||
2578 | else if (Pred->isStr("end")) | ||||
2579 | State = End; | ||||
2580 | else { | ||||
2581 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) | ||||
2582 | << Ext->isStr("all"); | ||||
2583 | return; | ||||
2584 | } | ||||
2585 | SourceLocation StateLoc = Tok.getLocation(); | ||||
2586 | |||||
2587 | PP.Lex(Tok); | ||||
2588 | if (Tok.isNot(tok::eod)) { | ||||
2589 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | ||||
2590 | "OPENCL EXTENSION"; | ||||
2591 | return; | ||||
2592 | } | ||||
2593 | |||||
2594 | auto Info = PP.getPreprocessorAllocator().Allocate<OpenCLExtData>(1); | ||||
2595 | Info->first = Ext; | ||||
2596 | Info->second = State; | ||||
2597 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
2598 | 1); | ||||
2599 | Toks[0].startToken(); | ||||
2600 | Toks[0].setKind(tok::annot_pragma_opencl_extension); | ||||
2601 | Toks[0].setLocation(NameLoc); | ||||
2602 | Toks[0].setAnnotationValue(static_cast<void*>(Info)); | ||||
2603 | Toks[0].setAnnotationEndLoc(StateLoc); | ||||
2604 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
2605 | /*IsReinject=*/false); | ||||
2606 | |||||
2607 | if (PP.getPPCallbacks()) | ||||
2608 | PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, Ext, | ||||
2609 | StateLoc, State); | ||||
2610 | } | ||||
2611 | |||||
2612 | /// Handle '#pragma omp ...' when OpenMP is disabled. | ||||
2613 | /// | ||||
2614 | void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, | ||||
2615 | PragmaIntroducer Introducer, | ||||
2616 | Token &FirstTok) { | ||||
2617 | if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored, | ||||
2618 | FirstTok.getLocation())) { | ||||
2619 | PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); | ||||
2620 | PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored, | ||||
2621 | diag::Severity::Ignored, SourceLocation()); | ||||
2622 | } | ||||
2623 | PP.DiscardUntilEndOfDirective(); | ||||
2624 | } | ||||
2625 | |||||
2626 | /// Handle '#pragma omp ...' when OpenMP is enabled. | ||||
2627 | /// | ||||
2628 | void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, | ||||
2629 | PragmaIntroducer Introducer, | ||||
2630 | Token &FirstTok) { | ||||
2631 | SmallVector<Token, 16> Pragma; | ||||
2632 | Token Tok; | ||||
2633 | Tok.startToken(); | ||||
2634 | Tok.setKind(tok::annot_pragma_openmp); | ||||
2635 | Tok.setLocation(Introducer.Loc); | ||||
2636 | |||||
2637 | while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) { | ||||
2638 | Pragma.push_back(Tok); | ||||
2639 | PP.Lex(Tok); | ||||
2640 | if (Tok.is(tok::annot_pragma_openmp)) { | ||||
2641 | PP.Diag(Tok, diag::err_omp_unexpected_directive) << 0; | ||||
2642 | unsigned InnerPragmaCnt = 1; | ||||
2643 | while (InnerPragmaCnt != 0) { | ||||
2644 | PP.Lex(Tok); | ||||
2645 | if (Tok.is(tok::annot_pragma_openmp)) | ||||
2646 | ++InnerPragmaCnt; | ||||
2647 | else if (Tok.is(tok::annot_pragma_openmp_end)) | ||||
2648 | --InnerPragmaCnt; | ||||
2649 | } | ||||
2650 | PP.Lex(Tok); | ||||
2651 | } | ||||
2652 | } | ||||
2653 | SourceLocation EodLoc = Tok.getLocation(); | ||||
2654 | Tok.startToken(); | ||||
2655 | Tok.setKind(tok::annot_pragma_openmp_end); | ||||
2656 | Tok.setLocation(EodLoc); | ||||
2657 | Pragma.push_back(Tok); | ||||
2658 | |||||
2659 | auto Toks = std::make_unique<Token[]>(Pragma.size()); | ||||
2660 | std::copy(Pragma.begin(), Pragma.end(), Toks.get()); | ||||
2661 | PP.EnterTokenStream(std::move(Toks), Pragma.size(), | ||||
2662 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
2663 | } | ||||
2664 | |||||
2665 | /// Handle '#pragma pointers_to_members' | ||||
2666 | // The grammar for this pragma is as follows: | ||||
2667 | // | ||||
2668 | // <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance' | ||||
2669 | // | ||||
2670 | // #pragma pointers_to_members '(' 'best_case' ')' | ||||
2671 | // #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')' | ||||
2672 | // #pragma pointers_to_members '(' inheritance-model ')' | ||||
2673 | void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, | ||||
2674 | PragmaIntroducer Introducer, | ||||
2675 | Token &Tok) { | ||||
2676 | SourceLocation PointersToMembersLoc = Tok.getLocation(); | ||||
2677 | PP.Lex(Tok); | ||||
2678 | if (Tok.isNot(tok::l_paren)) { | ||||
2679 | PP.Diag(PointersToMembersLoc, diag::warn_pragma_expected_lparen) | ||||
2680 | << "pointers_to_members"; | ||||
2681 | return; | ||||
2682 | } | ||||
2683 | PP.Lex(Tok); | ||||
2684 | const IdentifierInfo *Arg = Tok.getIdentifierInfo(); | ||||
2685 | if (!Arg) { | ||||
2686 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
2687 | << "pointers_to_members"; | ||||
2688 | return; | ||||
2689 | } | ||||
2690 | PP.Lex(Tok); | ||||
2691 | |||||
2692 | LangOptions::PragmaMSPointersToMembersKind RepresentationMethod; | ||||
2693 | if (Arg->isStr("best_case")) { | ||||
2694 | RepresentationMethod = LangOptions::PPTMK_BestCase; | ||||
2695 | } else { | ||||
2696 | if (Arg->isStr("full_generality")) { | ||||
2697 | if (Tok.is(tok::comma)) { | ||||
2698 | PP.Lex(Tok); | ||||
2699 | |||||
2700 | Arg = Tok.getIdentifierInfo(); | ||||
2701 | if (!Arg) { | ||||
2702 | PP.Diag(Tok.getLocation(), | ||||
2703 | diag::err_pragma_pointers_to_members_unknown_kind) | ||||
2704 | << Tok.getKind() << /*OnlyInheritanceModels*/ 0; | ||||
2705 | return; | ||||
2706 | } | ||||
2707 | PP.Lex(Tok); | ||||
2708 | } else if (Tok.is(tok::r_paren)) { | ||||
2709 | // #pragma pointers_to_members(full_generality) implicitly specifies | ||||
2710 | // virtual_inheritance. | ||||
2711 | Arg = nullptr; | ||||
2712 | RepresentationMethod = LangOptions::PPTMK_FullGeneralityVirtualInheritance; | ||||
2713 | } else { | ||||
2714 | PP.Diag(Tok.getLocation(), diag::err_expected_punc) | ||||
2715 | << "full_generality"; | ||||
2716 | return; | ||||
2717 | } | ||||
2718 | } | ||||
2719 | |||||
2720 | if (Arg) { | ||||
2721 | if (Arg->isStr("single_inheritance")) { | ||||
2722 | RepresentationMethod = | ||||
2723 | LangOptions::PPTMK_FullGeneralitySingleInheritance; | ||||
2724 | } else if (Arg->isStr("multiple_inheritance")) { | ||||
2725 | RepresentationMethod = | ||||
2726 | LangOptions::PPTMK_FullGeneralityMultipleInheritance; | ||||
2727 | } else if (Arg->isStr("virtual_inheritance")) { | ||||
2728 | RepresentationMethod = | ||||
2729 | LangOptions::PPTMK_FullGeneralityVirtualInheritance; | ||||
2730 | } else { | ||||
2731 | PP.Diag(Tok.getLocation(), | ||||
2732 | diag::err_pragma_pointers_to_members_unknown_kind) | ||||
2733 | << Arg << /*HasPointerDeclaration*/ 1; | ||||
2734 | return; | ||||
2735 | } | ||||
2736 | } | ||||
2737 | } | ||||
2738 | |||||
2739 | if (Tok.isNot(tok::r_paren)) { | ||||
2740 | PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after) | ||||
2741 | << (Arg ? Arg->getName() : "full_generality"); | ||||
2742 | return; | ||||
2743 | } | ||||
2744 | |||||
2745 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2746 | PP.Lex(Tok); | ||||
2747 | if (Tok.isNot(tok::eod)) { | ||||
2748 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2749 | << "pointers_to_members"; | ||||
2750 | return; | ||||
2751 | } | ||||
2752 | |||||
2753 | Token AnnotTok; | ||||
2754 | AnnotTok.startToken(); | ||||
2755 | AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members); | ||||
2756 | AnnotTok.setLocation(PointersToMembersLoc); | ||||
2757 | AnnotTok.setAnnotationEndLoc(EndLoc); | ||||
2758 | AnnotTok.setAnnotationValue( | ||||
2759 | reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod))); | ||||
2760 | PP.EnterToken(AnnotTok, /*IsReinject=*/true); | ||||
2761 | } | ||||
2762 | |||||
2763 | /// Handle '#pragma vtordisp' | ||||
2764 | // The grammar for this pragma is as follows: | ||||
2765 | // | ||||
2766 | // <vtordisp-mode> ::= ('off' | 'on' | '0' | '1' | '2' ) | ||||
2767 | // | ||||
2768 | // #pragma vtordisp '(' ['push' ','] vtordisp-mode ')' | ||||
2769 | // #pragma vtordisp '(' 'pop' ')' | ||||
2770 | // #pragma vtordisp '(' ')' | ||||
2771 | void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, | ||||
2772 | PragmaIntroducer Introducer, Token &Tok) { | ||||
2773 | SourceLocation VtorDispLoc = Tok.getLocation(); | ||||
2774 | PP.Lex(Tok); | ||||
2775 | if (Tok.isNot(tok::l_paren)) { | ||||
2776 | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_lparen) << "vtordisp"; | ||||
2777 | return; | ||||
2778 | } | ||||
2779 | PP.Lex(Tok); | ||||
2780 | |||||
2781 | Sema::PragmaMsStackAction Action = Sema::PSK_Set; | ||||
2782 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2783 | if (II) { | ||||
2784 | if (II->isStr("push")) { | ||||
2785 | // #pragma vtordisp(push, mode) | ||||
2786 | PP.Lex(Tok); | ||||
2787 | if (Tok.isNot(tok::comma)) { | ||||
2788 | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_punc) << "vtordisp"; | ||||
2789 | return; | ||||
2790 | } | ||||
2791 | PP.Lex(Tok); | ||||
2792 | Action = Sema::PSK_Push_Set; | ||||
2793 | // not push, could be on/off | ||||
2794 | } else if (II->isStr("pop")) { | ||||
2795 | // #pragma vtordisp(pop) | ||||
2796 | PP.Lex(Tok); | ||||
2797 | Action = Sema::PSK_Pop; | ||||
2798 | } | ||||
2799 | // not push or pop, could be on/off | ||||
2800 | } else { | ||||
2801 | if (Tok.is(tok::r_paren)) { | ||||
2802 | // #pragma vtordisp() | ||||
2803 | Action = Sema::PSK_Reset; | ||||
2804 | } | ||||
2805 | } | ||||
2806 | |||||
2807 | |||||
2808 | uint64_t Value = 0; | ||||
2809 | if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) { | ||||
2810 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2811 | if (II && II->isStr("off")) { | ||||
2812 | PP.Lex(Tok); | ||||
2813 | Value = 0; | ||||
2814 | } else if (II && II->isStr("on")) { | ||||
2815 | PP.Lex(Tok); | ||||
2816 | Value = 1; | ||||
2817 | } else if (Tok.is(tok::numeric_constant) && | ||||
2818 | PP.parseSimpleIntegerLiteral(Tok, Value)) { | ||||
2819 | if (Value > 2) { | ||||
2820 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer) | ||||
2821 | << 0 << 2 << "vtordisp"; | ||||
2822 | return; | ||||
2823 | } | ||||
2824 | } else { | ||||
2825 | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) | ||||
2826 | << "vtordisp"; | ||||
2827 | return; | ||||
2828 | } | ||||
2829 | } | ||||
2830 | |||||
2831 | // Finish the pragma: ')' $ | ||||
2832 | if (Tok.isNot(tok::r_paren)) { | ||||
2833 | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp"; | ||||
2834 | return; | ||||
2835 | } | ||||
2836 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2837 | PP.Lex(Tok); | ||||
2838 | if (Tok.isNot(tok::eod)) { | ||||
2839 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2840 | << "vtordisp"; | ||||
2841 | return; | ||||
2842 | } | ||||
2843 | |||||
2844 | // Enter the annotation. | ||||
2845 | Token AnnotTok; | ||||
2846 | AnnotTok.startToken(); | ||||
2847 | AnnotTok.setKind(tok::annot_pragma_ms_vtordisp); | ||||
2848 | AnnotTok.setLocation(VtorDispLoc); | ||||
2849 | AnnotTok.setAnnotationEndLoc(EndLoc); | ||||
2850 | AnnotTok.setAnnotationValue(reinterpret_cast<void *>( | ||||
2851 | static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF)))); | ||||
2852 | PP.EnterToken(AnnotTok, /*IsReinject=*/false); | ||||
2853 | } | ||||
2854 | |||||
2855 | /// Handle all MS pragmas. Simply forwards the tokens after inserting | ||||
2856 | /// an annotation token. | ||||
2857 | void PragmaMSPragma::HandlePragma(Preprocessor &PP, | ||||
2858 | PragmaIntroducer Introducer, Token &Tok) { | ||||
2859 | Token EoF, AnnotTok; | ||||
2860 | EoF.startToken(); | ||||
2861 | EoF.setKind(tok::eof); | ||||
2862 | AnnotTok.startToken(); | ||||
2863 | AnnotTok.setKind(tok::annot_pragma_ms_pragma); | ||||
2864 | AnnotTok.setLocation(Tok.getLocation()); | ||||
2865 | AnnotTok.setAnnotationEndLoc(Tok.getLocation()); | ||||
2866 | SmallVector<Token, 8> TokenVector; | ||||
2867 | // Suck up all of the tokens before the eod. | ||||
2868 | for (; Tok.isNot(tok::eod); PP.Lex(Tok)) { | ||||
2869 | TokenVector.push_back(Tok); | ||||
2870 | AnnotTok.setAnnotationEndLoc(Tok.getLocation()); | ||||
2871 | } | ||||
2872 | // Add a sentinel EoF token to the end of the list. | ||||
2873 | TokenVector.push_back(EoF); | ||||
2874 | // We must allocate this array with new because EnterTokenStream is going to | ||||
2875 | // delete it later. | ||||
2876 | markAsReinjectedForRelexing(TokenVector); | ||||
2877 | auto TokenArray = std::make_unique<Token[]>(TokenVector.size()); | ||||
2878 | std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get()); | ||||
2879 | auto Value = new (PP.getPreprocessorAllocator()) | ||||
2880 | std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray), | ||||
2881 | TokenVector.size()); | ||||
2882 | AnnotTok.setAnnotationValue(Value); | ||||
2883 | PP.EnterToken(AnnotTok, /*IsReinject*/ false); | ||||
2884 | } | ||||
2885 | |||||
2886 | /// Handle the \#pragma float_control extension. | ||||
2887 | /// | ||||
2888 | /// The syntax is: | ||||
2889 | /// \code | ||||
2890 | /// #pragma float_control(keyword[, setting] [,push]) | ||||
2891 | /// \endcode | ||||
2892 | /// Where 'keyword' and 'setting' are identifiers. | ||||
2893 | // 'keyword' can be: precise, except, push, pop | ||||
2894 | // 'setting' can be: on, off | ||||
2895 | /// The optional arguments 'setting' and 'push' are supported only | ||||
2896 | /// when the keyword is 'precise' or 'except'. | ||||
2897 | void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP, | ||||
2898 | PragmaIntroducer Introducer, | ||||
2899 | Token &Tok) { | ||||
2900 | Sema::PragmaMsStackAction Action = Sema::PSK_Set; | ||||
2901 | SourceLocation FloatControlLoc = Tok.getLocation(); | ||||
2902 | Token PragmaName = Tok; | ||||
2903 | if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { | ||||
2904 | PP.Diag(Tok.getLocation(), diag::warn_pragma_fp_ignored) | ||||
2905 | << PragmaName.getIdentifierInfo()->getName(); | ||||
2906 | return; | ||||
2907 | } | ||||
2908 | PP.Lex(Tok); | ||||
2909 | if (Tok.isNot(tok::l_paren)) { | ||||
2910 | PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren; | ||||
2911 | return; | ||||
2912 | } | ||||
2913 | |||||
2914 | // Read the identifier. | ||||
2915 | PP.Lex(Tok); | ||||
2916 | if (Tok.isNot(tok::identifier)) { | ||||
2917 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2918 | return; | ||||
2919 | } | ||||
2920 | |||||
2921 | // Verify that this is one of the float control options. | ||||
2922 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
2923 | PragmaFloatControlKind Kind = | ||||
2924 | llvm::StringSwitch<PragmaFloatControlKind>(II->getName()) | ||||
2925 | .Case("precise", PFC_Precise) | ||||
2926 | .Case("except", PFC_Except) | ||||
2927 | .Case("push", PFC_Push) | ||||
2928 | .Case("pop", PFC_Pop) | ||||
2929 | .Default(PFC_Unknown); | ||||
2930 | PP.Lex(Tok); // the identifier | ||||
2931 | if (Kind == PFC_Unknown) { | ||||
2932 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2933 | return; | ||||
2934 | } else if (Kind == PFC_Push || Kind == PFC_Pop) { | ||||
2935 | if (Tok.isNot(tok::r_paren)) { | ||||
2936 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2937 | return; | ||||
2938 | } | ||||
2939 | PP.Lex(Tok); // Eat the r_paren | ||||
2940 | Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push; | ||||
2941 | } else { | ||||
2942 | if (Tok.is(tok::r_paren)) | ||||
2943 | // Selecting Precise or Except | ||||
2944 | PP.Lex(Tok); // the r_paren | ||||
2945 | else if (Tok.isNot(tok::comma)) { | ||||
2946 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2947 | return; | ||||
2948 | } else { | ||||
2949 | PP.Lex(Tok); // , | ||||
2950 | if (!Tok.isAnyIdentifier()) { | ||||
2951 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2952 | return; | ||||
2953 | } | ||||
2954 | StringRef PushOnOff = Tok.getIdentifierInfo()->getName(); | ||||
2955 | if (PushOnOff == "on") | ||||
2956 | // Kind is set correctly | ||||
2957 | ; | ||||
2958 | else if (PushOnOff == "off") { | ||||
2959 | if (Kind == PFC_Precise) | ||||
2960 | Kind = PFC_NoPrecise; | ||||
2961 | if (Kind == PFC_Except) | ||||
2962 | Kind = PFC_NoExcept; | ||||
2963 | } else if (PushOnOff == "push") { | ||||
2964 | Action = Sema::PSK_Push_Set; | ||||
2965 | } else { | ||||
2966 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2967 | return; | ||||
2968 | } | ||||
2969 | PP.Lex(Tok); // the identifier | ||||
2970 | if (Tok.is(tok::comma)) { | ||||
2971 | PP.Lex(Tok); // , | ||||
2972 | if (!Tok.isAnyIdentifier()) { | ||||
2973 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2974 | return; | ||||
2975 | } | ||||
2976 | StringRef ExpectedPush = Tok.getIdentifierInfo()->getName(); | ||||
2977 | if (ExpectedPush == "push") { | ||||
2978 | Action = Sema::PSK_Push_Set; | ||||
2979 | } else { | ||||
2980 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2981 | return; | ||||
2982 | } | ||||
2983 | PP.Lex(Tok); // the push identifier | ||||
2984 | } | ||||
2985 | if (Tok.isNot(tok::r_paren)) { | ||||
2986 | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | ||||
2987 | return; | ||||
2988 | } | ||||
2989 | PP.Lex(Tok); // the r_paren | ||||
2990 | } | ||||
2991 | } | ||||
2992 | SourceLocation EndLoc = Tok.getLocation(); | ||||
2993 | if (Tok.isNot(tok::eod)) { | ||||
2994 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
2995 | << "float_control"; | ||||
2996 | return; | ||||
2997 | } | ||||
2998 | |||||
2999 | // Note: there is no accomodation for PP callback for this pragma. | ||||
3000 | |||||
3001 | // Enter the annotation. | ||||
3002 | auto TokenArray = std::make_unique<Token[]>(1); | ||||
3003 | TokenArray[0].startToken(); | ||||
3004 | TokenArray[0].setKind(tok::annot_pragma_float_control); | ||||
3005 | TokenArray[0].setLocation(FloatControlLoc); | ||||
3006 | TokenArray[0].setAnnotationEndLoc(EndLoc); | ||||
3007 | // Create an encoding of Action and Value by shifting the Action into | ||||
3008 | // the high 16 bits then union with the Kind. | ||||
3009 | TokenArray[0].setAnnotationValue(reinterpret_cast<void *>( | ||||
3010 | static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF)))); | ||||
3011 | PP.EnterTokenStream(std::move(TokenArray), 1, | ||||
3012 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
3013 | } | ||||
3014 | |||||
3015 | /// Handle the Microsoft \#pragma detect_mismatch extension. | ||||
3016 | /// | ||||
3017 | /// The syntax is: | ||||
3018 | /// \code | ||||
3019 | /// #pragma detect_mismatch("name", "value") | ||||
3020 | /// \endcode | ||||
3021 | /// Where 'name' and 'value' are quoted strings. The values are embedded in | ||||
3022 | /// the object file and passed along to the linker. If the linker detects a | ||||
3023 | /// mismatch in the object file's values for the given name, a LNK2038 error | ||||
3024 | /// is emitted. See MSDN for more details. | ||||
3025 | void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, | ||||
3026 | PragmaIntroducer Introducer, | ||||
3027 | Token &Tok) { | ||||
3028 | SourceLocation DetectMismatchLoc = Tok.getLocation(); | ||||
3029 | PP.Lex(Tok); | ||||
3030 | if (Tok.isNot(tok::l_paren)) { | ||||
3031 | PP.Diag(DetectMismatchLoc, diag::err_expected) << tok::l_paren; | ||||
3032 | return; | ||||
3033 | } | ||||
3034 | |||||
3035 | // Read the name to embed, which must be a string literal. | ||||
3036 | std::string NameString; | ||||
3037 | if (!PP.LexStringLiteral(Tok, NameString, | ||||
3038 | "pragma detect_mismatch", | ||||
3039 | /*AllowMacroExpansion=*/true)) | ||||
3040 | return; | ||||
3041 | |||||
3042 | // Read the comma followed by a second string literal. | ||||
3043 | std::string ValueString; | ||||
3044 | if (Tok.isNot(tok::comma)) { | ||||
3045 | PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); | ||||
3046 | return; | ||||
3047 | } | ||||
3048 | |||||
3049 | if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch", | ||||
3050 | /*AllowMacroExpansion=*/true)) | ||||
3051 | return; | ||||
3052 | |||||
3053 | if (Tok.isNot(tok::r_paren)) { | ||||
3054 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | ||||
3055 | return; | ||||
3056 | } | ||||
3057 | PP.Lex(Tok); // Eat the r_paren. | ||||
3058 | |||||
3059 | if (Tok.isNot(tok::eod)) { | ||||
3060 | PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); | ||||
3061 | return; | ||||
3062 | } | ||||
3063 | |||||
3064 | // If the pragma is lexically sound, notify any interested PPCallbacks. | ||||
3065 | if (PP.getPPCallbacks()) | ||||
3066 | PP.getPPCallbacks()->PragmaDetectMismatch(DetectMismatchLoc, NameString, | ||||
3067 | ValueString); | ||||
3068 | |||||
3069 | Actions.ActOnPragmaDetectMismatch(DetectMismatchLoc, NameString, ValueString); | ||||
3070 | } | ||||
3071 | |||||
3072 | /// Handle the microsoft \#pragma comment extension. | ||||
3073 | /// | ||||
3074 | /// The syntax is: | ||||
3075 | /// \code | ||||
3076 | /// #pragma comment(linker, "foo") | ||||
3077 | /// \endcode | ||||
3078 | /// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. | ||||
3079 | /// "foo" is a string, which is fully macro expanded, and permits string | ||||
3080 | /// concatenation, embedded escape characters etc. See MSDN for more details. | ||||
3081 | void PragmaCommentHandler::HandlePragma(Preprocessor &PP, | ||||
3082 | PragmaIntroducer Introducer, | ||||
3083 | Token &Tok) { | ||||
3084 | SourceLocation CommentLoc = Tok.getLocation(); | ||||
3085 | PP.Lex(Tok); | ||||
3086 | if (Tok.isNot(tok::l_paren)) { | ||||
3087 | PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); | ||||
3088 | return; | ||||
3089 | } | ||||
3090 | |||||
3091 | // Read the identifier. | ||||
3092 | PP.Lex(Tok); | ||||
3093 | if (Tok.isNot(tok::identifier)) { | ||||
3094 | PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); | ||||
3095 | return; | ||||
3096 | } | ||||
3097 | |||||
3098 | // Verify that this is one of the 5 explicitly listed options. | ||||
3099 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3100 | PragmaMSCommentKind Kind = | ||||
3101 | llvm::StringSwitch<PragmaMSCommentKind>(II->getName()) | ||||
3102 | .Case("linker", PCK_Linker) | ||||
3103 | .Case("lib", PCK_Lib) | ||||
3104 | .Case("compiler", PCK_Compiler) | ||||
3105 | .Case("exestr", PCK_ExeStr) | ||||
3106 | .Case("user", PCK_User) | ||||
3107 | .Default(PCK_Unknown); | ||||
3108 | if (Kind == PCK_Unknown) { | ||||
3109 | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); | ||||
3110 | return; | ||||
3111 | } | ||||
3112 | |||||
3113 | if (PP.getTargetInfo().getTriple().isOSBinFormatELF() && Kind != PCK_Lib) { | ||||
3114 | PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) | ||||
3115 | << II->getName(); | ||||
3116 | return; | ||||
3117 | } | ||||
3118 | |||||
3119 | // Read the optional string if present. | ||||
3120 | PP.Lex(Tok); | ||||
3121 | std::string ArgumentString; | ||||
3122 | if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, | ||||
3123 | "pragma comment", | ||||
3124 | /*AllowMacroExpansion=*/true)) | ||||
3125 | return; | ||||
3126 | |||||
3127 | // FIXME: warn that 'exestr' is deprecated. | ||||
3128 | // FIXME: If the kind is "compiler" warn if the string is present (it is | ||||
3129 | // ignored). | ||||
3130 | // The MSDN docs say that "lib" and "linker" require a string and have a short | ||||
3131 | // list of linker options they support, but in practice MSVC doesn't | ||||
3132 | // issue a diagnostic. Therefore neither does clang. | ||||
3133 | |||||
3134 | if (Tok.isNot(tok::r_paren)) { | ||||
3135 | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); | ||||
3136 | return; | ||||
3137 | } | ||||
3138 | PP.Lex(Tok); // eat the r_paren. | ||||
3139 | |||||
3140 | if (Tok.isNot(tok::eod)) { | ||||
3141 | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); | ||||
3142 | return; | ||||
3143 | } | ||||
3144 | |||||
3145 | // If the pragma is lexically sound, notify any interested PPCallbacks. | ||||
3146 | if (PP.getPPCallbacks()) | ||||
3147 | PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); | ||||
3148 | |||||
3149 | Actions.ActOnPragmaMSComment(CommentLoc, Kind, ArgumentString); | ||||
3150 | } | ||||
3151 | |||||
3152 | // #pragma clang optimize off | ||||
3153 | // #pragma clang optimize on | ||||
3154 | void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, | ||||
3155 | PragmaIntroducer Introducer, | ||||
3156 | Token &FirstToken) { | ||||
3157 | Token Tok; | ||||
3158 | PP.Lex(Tok); | ||||
3159 | if (Tok.is(tok::eod)) { | ||||
3160 | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | ||||
3161 | << "clang optimize" << /*Expected=*/true << "'on' or 'off'"; | ||||
3162 | return; | ||||
3163 | } | ||||
3164 | if (Tok.isNot(tok::identifier)) { | ||||
3165 | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument) | ||||
3166 | << PP.getSpelling(Tok); | ||||
3167 | return; | ||||
3168 | } | ||||
3169 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3170 | // The only accepted values are 'on' or 'off'. | ||||
3171 | bool IsOn = false; | ||||
3172 | if (II->isStr("on")) { | ||||
3173 | IsOn = true; | ||||
3174 | } else if (!II->isStr("off")) { | ||||
3175 | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument) | ||||
3176 | << PP.getSpelling(Tok); | ||||
3177 | return; | ||||
3178 | } | ||||
3179 | PP.Lex(Tok); | ||||
3180 | |||||
3181 | if (Tok.isNot(tok::eod)) { | ||||
3182 | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument) | ||||
3183 | << PP.getSpelling(Tok); | ||||
3184 | return; | ||||
3185 | } | ||||
3186 | |||||
3187 | Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation()); | ||||
3188 | } | ||||
3189 | |||||
3190 | namespace { | ||||
3191 | /// Used as the annotation value for tok::annot_pragma_fp. | ||||
3192 | struct TokFPAnnotValue { | ||||
3193 | enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod }; | ||||
3194 | enum FlagValues { On, Off, Fast }; | ||||
3195 | |||||
3196 | std::optional<LangOptions::FPModeKind> ContractValue; | ||||
3197 | std::optional<LangOptions::FPModeKind> ReassociateValue; | ||||
3198 | std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue; | ||||
3199 | std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue; | ||||
3200 | }; | ||||
3201 | } // end anonymous namespace | ||||
3202 | |||||
3203 | void PragmaFPHandler::HandlePragma(Preprocessor &PP, | ||||
3204 | PragmaIntroducer Introducer, Token &Tok) { | ||||
3205 | // fp | ||||
3206 | Token PragmaName = Tok; | ||||
3207 | SmallVector<Token, 1> TokenList; | ||||
3208 | |||||
3209 | PP.Lex(Tok); | ||||
3210 | if (Tok.isNot(tok::identifier)) { | ||||
3211 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) | ||||
3212 | << /*MissingOption=*/true << ""; | ||||
3213 | return; | ||||
3214 | } | ||||
3215 | |||||
3216 | auto *AnnotValue = new (PP.getPreprocessorAllocator()) TokFPAnnotValue; | ||||
3217 | while (Tok.is(tok::identifier)) { | ||||
3218 | IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); | ||||
3219 | |||||
3220 | auto FlagKind = | ||||
3221 | llvm::StringSwitch<std::optional<TokFPAnnotValue::FlagKinds>>( | ||||
3222 | OptionInfo->getName()) | ||||
3223 | .Case("contract", TokFPAnnotValue::Contract) | ||||
3224 | .Case("reassociate", TokFPAnnotValue::Reassociate) | ||||
3225 | .Case("exceptions", TokFPAnnotValue::Exceptions) | ||||
3226 | .Case("eval_method", TokFPAnnotValue::EvalMethod) | ||||
3227 | .Default(std::nullopt); | ||||
3228 | if (!FlagKind) { | ||||
3229 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) | ||||
3230 | << /*MissingOption=*/false << OptionInfo; | ||||
3231 | return; | ||||
3232 | } | ||||
3233 | PP.Lex(Tok); | ||||
3234 | |||||
3235 | // Read '(' | ||||
3236 | if (Tok.isNot(tok::l_paren)) { | ||||
3237 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | ||||
3238 | return; | ||||
3239 | } | ||||
3240 | PP.Lex(Tok); | ||||
3241 | bool isEvalMethodDouble = | ||||
3242 | Tok.is(tok::kw_double) && FlagKind == TokFPAnnotValue::EvalMethod; | ||||
3243 | |||||
3244 | // Don't diagnose if we have an eval_metod pragma with "double" kind. | ||||
3245 | if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) { | ||||
3246 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | ||||
3247 | << PP.getSpelling(Tok) << OptionInfo->getName() | ||||
3248 | << static_cast<int>(*FlagKind); | ||||
3249 | return; | ||||
3250 | } | ||||
3251 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3252 | |||||
3253 | if (FlagKind == TokFPAnnotValue::Contract) { | ||||
3254 | AnnotValue->ContractValue = | ||||
3255 | llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>( | ||||
3256 | II->getName()) | ||||
3257 | .Case("on", LangOptions::FPModeKind::FPM_On) | ||||
3258 | .Case("off", LangOptions::FPModeKind::FPM_Off) | ||||
3259 | .Case("fast", LangOptions::FPModeKind::FPM_Fast) | ||||
3260 | .Default(std::nullopt); | ||||
3261 | if (!AnnotValue->ContractValue) { | ||||
3262 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | ||||
3263 | << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; | ||||
3264 | return; | ||||
3265 | } | ||||
3266 | } else if (FlagKind == TokFPAnnotValue::Reassociate) { | ||||
3267 | AnnotValue->ReassociateValue = | ||||
3268 | llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>( | ||||
3269 | II->getName()) | ||||
3270 | .Case("on", LangOptions::FPModeKind::FPM_On) | ||||
3271 | .Case("off", LangOptions::FPModeKind::FPM_Off) | ||||
3272 | .Default(std::nullopt); | ||||
3273 | if (!AnnotValue->ReassociateValue) { | ||||
3274 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | ||||
3275 | << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; | ||||
3276 | return; | ||||
3277 | } | ||||
3278 | } else if (FlagKind == TokFPAnnotValue::Exceptions) { | ||||
3279 | AnnotValue->ExceptionsValue = | ||||
3280 | llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>( | ||||
3281 | II->getName()) | ||||
3282 | .Case("ignore", LangOptions::FPE_Ignore) | ||||
3283 | .Case("maytrap", LangOptions::FPE_MayTrap) | ||||
3284 | .Case("strict", LangOptions::FPE_Strict) | ||||
3285 | .Default(std::nullopt); | ||||
3286 | if (!AnnotValue->ExceptionsValue) { | ||||
3287 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | ||||
3288 | << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; | ||||
3289 | return; | ||||
3290 | } | ||||
3291 | } else if (FlagKind == TokFPAnnotValue::EvalMethod) { | ||||
3292 | AnnotValue->EvalMethodValue = | ||||
3293 | llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>( | ||||
3294 | II->getName()) | ||||
3295 | .Case("source", LangOptions::FPEvalMethodKind::FEM_Source) | ||||
3296 | .Case("double", LangOptions::FPEvalMethodKind::FEM_Double) | ||||
3297 | .Case("extended", LangOptions::FPEvalMethodKind::FEM_Extended) | ||||
3298 | .Default(std::nullopt); | ||||
3299 | if (!AnnotValue->EvalMethodValue) { | ||||
3300 | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | ||||
3301 | << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind; | ||||
3302 | return; | ||||
3303 | } | ||||
3304 | } | ||||
3305 | PP.Lex(Tok); | ||||
3306 | |||||
3307 | // Read ')' | ||||
3308 | if (Tok.isNot(tok::r_paren)) { | ||||
3309 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | ||||
3310 | return; | ||||
3311 | } | ||||
3312 | PP.Lex(Tok); | ||||
3313 | } | ||||
3314 | |||||
3315 | if (Tok.isNot(tok::eod)) { | ||||
3316 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3317 | << "clang fp"; | ||||
3318 | return; | ||||
3319 | } | ||||
3320 | |||||
3321 | Token FPTok; | ||||
3322 | FPTok.startToken(); | ||||
3323 | FPTok.setKind(tok::annot_pragma_fp); | ||||
3324 | FPTok.setLocation(PragmaName.getLocation()); | ||||
3325 | FPTok.setAnnotationEndLoc(PragmaName.getLocation()); | ||||
3326 | FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue)); | ||||
3327 | TokenList.push_back(FPTok); | ||||
3328 | |||||
3329 | auto TokenArray = std::make_unique<Token[]>(TokenList.size()); | ||||
3330 | std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); | ||||
3331 | |||||
3332 | PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), | ||||
3333 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
3334 | } | ||||
3335 | |||||
3336 | void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP, | ||||
3337 | PragmaIntroducer Introducer, | ||||
3338 | Token &Tok) { | ||||
3339 | Token PragmaName = Tok; | ||||
3340 | SmallVector<Token, 1> TokenList; | ||||
3341 | if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { | ||||
3342 | PP.Diag(Tok.getLocation(), diag::warn_pragma_fp_ignored) | ||||
3343 | << PragmaName.getIdentifierInfo()->getName(); | ||||
3344 | return; | ||||
3345 | } | ||||
3346 | |||||
3347 | PP.Lex(Tok); | ||||
3348 | if (Tok.isNot(tok::identifier)) { | ||||
3349 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||||
3350 | << PragmaName.getIdentifierInfo()->getName(); | ||||
3351 | return; | ||||
3352 | } | ||||
3353 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3354 | |||||
3355 | auto RM = | ||||
3356 | llvm::StringSwitch<llvm::RoundingMode>(II->getName()) | ||||
3357 | .Case("FE_TOWARDZERO", llvm::RoundingMode::TowardZero) | ||||
3358 | .Case("FE_TONEAREST", llvm::RoundingMode::NearestTiesToEven) | ||||
3359 | .Case("FE_UPWARD", llvm::RoundingMode::TowardPositive) | ||||
3360 | .Case("FE_DOWNWARD", llvm::RoundingMode::TowardNegative) | ||||
3361 | .Case("FE_TONEARESTFROMZERO", llvm::RoundingMode::NearestTiesToAway) | ||||
3362 | .Case("FE_DYNAMIC", llvm::RoundingMode::Dynamic) | ||||
3363 | .Default(llvm::RoundingMode::Invalid); | ||||
3364 | if (RM == llvm::RoundingMode::Invalid) { | ||||
3365 | PP.Diag(Tok.getLocation(), diag::warn_stdc_unknown_rounding_mode); | ||||
3366 | return; | ||||
3367 | } | ||||
3368 | PP.Lex(Tok); | ||||
3369 | |||||
3370 | if (Tok.isNot(tok::eod)) { | ||||
3371 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3372 | << "STDC FENV_ROUND"; | ||||
3373 | return; | ||||
3374 | } | ||||
3375 | |||||
3376 | // Until the pragma is fully implemented, issue a warning. | ||||
3377 | PP.Diag(Tok.getLocation(), diag::warn_stdc_fenv_round_not_supported); | ||||
3378 | |||||
3379 | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | ||||
3380 | 1); | ||||
3381 | Toks[0].startToken(); | ||||
3382 | Toks[0].setKind(tok::annot_pragma_fenv_round); | ||||
3383 | Toks[0].setLocation(Tok.getLocation()); | ||||
3384 | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | ||||
3385 | Toks[0].setAnnotationValue( | ||||
3386 | reinterpret_cast<void *>(static_cast<uintptr_t>(RM))); | ||||
3387 | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | ||||
3388 | /*IsReinject=*/false); | ||||
3389 | } | ||||
3390 | |||||
3391 | void Parser::HandlePragmaFP() { | ||||
3392 | assert(Tok.is(tok::annot_pragma_fp))(static_cast <bool> (Tok.is(tok::annot_pragma_fp)) ? void (0) : __assert_fail ("Tok.is(tok::annot_pragma_fp)", "clang/lib/Parse/ParsePragma.cpp" , 3392, __extension__ __PRETTY_FUNCTION__)); | ||||
3393 | auto *AnnotValue = | ||||
3394 | reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue()); | ||||
3395 | |||||
3396 | if (AnnotValue->ReassociateValue) | ||||
3397 | Actions.ActOnPragmaFPReassociate(Tok.getLocation(), | ||||
3398 | *AnnotValue->ReassociateValue == | ||||
3399 | LangOptions::FPModeKind::FPM_On); | ||||
3400 | if (AnnotValue->ContractValue) | ||||
3401 | Actions.ActOnPragmaFPContract(Tok.getLocation(), | ||||
3402 | *AnnotValue->ContractValue); | ||||
3403 | if (AnnotValue->ExceptionsValue) | ||||
3404 | Actions.ActOnPragmaFPExceptions(Tok.getLocation(), | ||||
3405 | *AnnotValue->ExceptionsValue); | ||||
3406 | if (AnnotValue->EvalMethodValue) | ||||
3407 | Actions.ActOnPragmaFPEvalMethod(Tok.getLocation(), | ||||
3408 | *AnnotValue->EvalMethodValue); | ||||
3409 | ConsumeAnnotationToken(); | ||||
3410 | } | ||||
3411 | |||||
3412 | /// Parses loop or unroll pragma hint value and fills in Info. | ||||
3413 | static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, | ||||
3414 | Token Option, bool ValueInParens, | ||||
3415 | PragmaLoopHintInfo &Info) { | ||||
3416 | SmallVector<Token, 1> ValueList; | ||||
3417 | int OpenParens = ValueInParens ? 1 : 0; | ||||
3418 | // Read constant expression. | ||||
3419 | while (Tok.isNot(tok::eod)) { | ||||
3420 | if (Tok.is(tok::l_paren)) | ||||
3421 | OpenParens++; | ||||
3422 | else if (Tok.is(tok::r_paren)) { | ||||
3423 | OpenParens--; | ||||
3424 | if (OpenParens == 0 && ValueInParens) | ||||
3425 | break; | ||||
3426 | } | ||||
3427 | |||||
3428 | ValueList.push_back(Tok); | ||||
3429 | PP.Lex(Tok); | ||||
3430 | } | ||||
3431 | |||||
3432 | if (ValueInParens) { | ||||
3433 | // Read ')' | ||||
3434 | if (Tok.isNot(tok::r_paren)) { | ||||
3435 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | ||||
3436 | return true; | ||||
3437 | } | ||||
3438 | PP.Lex(Tok); | ||||
3439 | } | ||||
3440 | |||||
3441 | Token EOFTok; | ||||
3442 | EOFTok.startToken(); | ||||
3443 | EOFTok.setKind(tok::eof); | ||||
3444 | EOFTok.setLocation(Tok.getLocation()); | ||||
3445 | ValueList.push_back(EOFTok); // Terminates expression for parsing. | ||||
3446 | |||||
3447 | markAsReinjectedForRelexing(ValueList); | ||||
3448 | Info.Toks = llvm::ArrayRef(ValueList).copy(PP.getPreprocessorAllocator()); | ||||
3449 | |||||
3450 | Info.PragmaName = PragmaName; | ||||
3451 | Info.Option = Option; | ||||
3452 | return false; | ||||
3453 | } | ||||
3454 | |||||
3455 | /// Handle the \#pragma clang loop directive. | ||||
3456 | /// #pragma clang 'loop' loop-hints | ||||
3457 | /// | ||||
3458 | /// loop-hints: | ||||
3459 | /// loop-hint loop-hints[opt] | ||||
3460 | /// | ||||
3461 | /// loop-hint: | ||||
3462 | /// 'vectorize' '(' loop-hint-keyword ')' | ||||
3463 | /// 'interleave' '(' loop-hint-keyword ')' | ||||
3464 | /// 'unroll' '(' unroll-hint-keyword ')' | ||||
3465 | /// 'vectorize_predicate' '(' loop-hint-keyword ')' | ||||
3466 | /// 'vectorize_width' '(' loop-hint-value ')' | ||||
3467 | /// 'interleave_count' '(' loop-hint-value ')' | ||||
3468 | /// 'unroll_count' '(' loop-hint-value ')' | ||||
3469 | /// 'pipeline' '(' disable ')' | ||||
3470 | /// 'pipeline_initiation_interval' '(' loop-hint-value ')' | ||||
3471 | /// | ||||
3472 | /// loop-hint-keyword: | ||||
3473 | /// 'enable' | ||||
3474 | /// 'disable' | ||||
3475 | /// 'assume_safety' | ||||
3476 | /// | ||||
3477 | /// unroll-hint-keyword: | ||||
3478 | /// 'enable' | ||||
3479 | /// 'disable' | ||||
3480 | /// 'full' | ||||
3481 | /// | ||||
3482 | /// loop-hint-value: | ||||
3483 | /// constant-expression | ||||
3484 | /// | ||||
3485 | /// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to | ||||
3486 | /// try vectorizing the instructions of the loop it precedes. Specifying | ||||
3487 | /// interleave(enable) or interleave_count(_value_) instructs llvm to try | ||||
3488 | /// interleaving multiple iterations of the loop it precedes. The width of the | ||||
3489 | /// vector instructions is specified by vectorize_width() and the number of | ||||
3490 | /// interleaved loop iterations is specified by interleave_count(). Specifying a | ||||
3491 | /// value of 1 effectively disables vectorization/interleaving, even if it is | ||||
3492 | /// possible and profitable, and 0 is invalid. The loop vectorizer currently | ||||
3493 | /// only works on inner loops. | ||||
3494 | /// | ||||
3495 | /// The unroll and unroll_count directives control the concatenation | ||||
3496 | /// unroller. Specifying unroll(enable) instructs llvm to unroll the loop | ||||
3497 | /// completely if the trip count is known at compile time and unroll partially | ||||
3498 | /// if the trip count is not known. Specifying unroll(full) is similar to | ||||
3499 | /// unroll(enable) but will unroll the loop only if the trip count is known at | ||||
3500 | /// compile time. Specifying unroll(disable) disables unrolling for the | ||||
3501 | /// loop. Specifying unroll_count(_value_) instructs llvm to try to unroll the | ||||
3502 | /// loop the number of times indicated by the value. | ||||
3503 | void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, | ||||
3504 | PragmaIntroducer Introducer, | ||||
3505 | Token &Tok) { | ||||
3506 | // Incoming token is "loop" from "#pragma clang loop". | ||||
3507 | Token PragmaName = Tok; | ||||
3508 | SmallVector<Token, 1> TokenList; | ||||
3509 | |||||
3510 | // Lex the optimization option and verify it is an identifier. | ||||
3511 | PP.Lex(Tok); | ||||
3512 | if (Tok.isNot(tok::identifier)) { | ||||
3513 | PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) | ||||
3514 | << /*MissingOption=*/true << ""; | ||||
3515 | return; | ||||
3516 | } | ||||
3517 | |||||
3518 | while (Tok.is(tok::identifier)) { | ||||
3519 | Token Option = Tok; | ||||
3520 | IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); | ||||
3521 | |||||
3522 | bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName()) | ||||
3523 | .Case("vectorize", true) | ||||
3524 | .Case("interleave", true) | ||||
3525 | .Case("unroll", true) | ||||
3526 | .Case("distribute", true) | ||||
3527 | .Case("vectorize_predicate", true) | ||||
3528 | .Case("vectorize_width", true) | ||||
3529 | .Case("interleave_count", true) | ||||
3530 | .Case("unroll_count", true) | ||||
3531 | .Case("pipeline", true) | ||||
3532 | .Case("pipeline_initiation_interval", true) | ||||
3533 | .Default(false); | ||||
3534 | if (!OptionValid) { | ||||
3535 | PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) | ||||
3536 | << /*MissingOption=*/false << OptionInfo; | ||||
3537 | return; | ||||
3538 | } | ||||
3539 | PP.Lex(Tok); | ||||
3540 | |||||
3541 | // Read '(' | ||||
3542 | if (Tok.isNot(tok::l_paren)) { | ||||
3543 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | ||||
3544 | return; | ||||
3545 | } | ||||
3546 | PP.Lex(Tok); | ||||
3547 | |||||
3548 | auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; | ||||
3549 | if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true, | ||||
3550 | *Info)) | ||||
3551 | return; | ||||
3552 | |||||
3553 | // Generate the loop hint token. | ||||
3554 | Token LoopHintTok; | ||||
3555 | LoopHintTok.startToken(); | ||||
3556 | LoopHintTok.setKind(tok::annot_pragma_loop_hint); | ||||
3557 | LoopHintTok.setLocation(Introducer.Loc); | ||||
3558 | LoopHintTok.setAnnotationEndLoc(PragmaName.getLocation()); | ||||
3559 | LoopHintTok.setAnnotationValue(static_cast<void *>(Info)); | ||||
3560 | TokenList.push_back(LoopHintTok); | ||||
3561 | } | ||||
3562 | |||||
3563 | if (Tok.isNot(tok::eod)) { | ||||
3564 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3565 | << "clang loop"; | ||||
3566 | return; | ||||
3567 | } | ||||
3568 | |||||
3569 | auto TokenArray = std::make_unique<Token[]>(TokenList.size()); | ||||
3570 | std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); | ||||
3571 | |||||
3572 | PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), | ||||
3573 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
3574 | } | ||||
3575 | |||||
3576 | /// Handle the loop unroll optimization pragmas. | ||||
3577 | /// #pragma unroll | ||||
3578 | /// #pragma unroll unroll-hint-value | ||||
3579 | /// #pragma unroll '(' unroll-hint-value ')' | ||||
3580 | /// #pragma nounroll | ||||
3581 | /// #pragma unroll_and_jam | ||||
3582 | /// #pragma unroll_and_jam unroll-hint-value | ||||
3583 | /// #pragma unroll_and_jam '(' unroll-hint-value ')' | ||||
3584 | /// #pragma nounroll_and_jam | ||||
3585 | /// | ||||
3586 | /// unroll-hint-value: | ||||
3587 | /// constant-expression | ||||
3588 | /// | ||||
3589 | /// Loop unrolling hints can be specified with '#pragma unroll' or | ||||
3590 | /// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally | ||||
3591 | /// contained in parentheses. With no argument the directive instructs llvm to | ||||
3592 | /// try to unroll the loop completely. A positive integer argument can be | ||||
3593 | /// specified to indicate the number of times the loop should be unrolled. To | ||||
3594 | /// maximize compatibility with other compilers the unroll count argument can be | ||||
3595 | /// specified with or without parentheses. Specifying, '#pragma nounroll' | ||||
3596 | /// disables unrolling of the loop. | ||||
3597 | void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, | ||||
3598 | PragmaIntroducer Introducer, | ||||
3599 | Token &Tok) { | ||||
3600 | // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for | ||||
3601 | // "#pragma nounroll". | ||||
3602 | Token PragmaName = Tok; | ||||
3603 | PP.Lex(Tok); | ||||
3604 | auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; | ||||
3605 | if (Tok.is(tok::eod)) { | ||||
3606 | // nounroll or unroll pragma without an argument. | ||||
3607 | Info->PragmaName = PragmaName; | ||||
3608 | Info->Option.startToken(); | ||||
3609 | } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll" || | ||||
3610 | PragmaName.getIdentifierInfo()->getName() == "nounroll_and_jam") { | ||||
3611 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3612 | << PragmaName.getIdentifierInfo()->getName(); | ||||
3613 | return; | ||||
3614 | } else { | ||||
3615 | // Unroll pragma with an argument: "#pragma unroll N" or | ||||
3616 | // "#pragma unroll(N)". | ||||
3617 | // Read '(' if it exists. | ||||
3618 | bool ValueInParens = Tok.is(tok::l_paren); | ||||
3619 | if (ValueInParens) | ||||
3620 | PP.Lex(Tok); | ||||
3621 | |||||
3622 | Token Option; | ||||
3623 | Option.startToken(); | ||||
3624 | if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info)) | ||||
3625 | return; | ||||
3626 | |||||
3627 | // In CUDA, the argument to '#pragma unroll' should not be contained in | ||||
3628 | // parentheses. | ||||
3629 | if (PP.getLangOpts().CUDA && ValueInParens) | ||||
3630 | PP.Diag(Info->Toks[0].getLocation(), | ||||
3631 | diag::warn_pragma_unroll_cuda_value_in_parens); | ||||
3632 | |||||
3633 | if (Tok.isNot(tok::eod)) { | ||||
3634 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3635 | << "unroll"; | ||||
3636 | return; | ||||
3637 | } | ||||
3638 | } | ||||
3639 | |||||
3640 | // Generate the hint token. | ||||
3641 | auto TokenArray = std::make_unique<Token[]>(1); | ||||
3642 | TokenArray[0].startToken(); | ||||
3643 | TokenArray[0].setKind(tok::annot_pragma_loop_hint); | ||||
3644 | TokenArray[0].setLocation(Introducer.Loc); | ||||
3645 | TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation()); | ||||
3646 | TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); | ||||
3647 | PP.EnterTokenStream(std::move(TokenArray), 1, | ||||
3648 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
3649 | } | ||||
3650 | |||||
3651 | /// Handle the Microsoft \#pragma intrinsic extension. | ||||
3652 | /// | ||||
3653 | /// The syntax is: | ||||
3654 | /// \code | ||||
3655 | /// #pragma intrinsic(memset) | ||||
3656 | /// #pragma intrinsic(strlen, memcpy) | ||||
3657 | /// \endcode | ||||
3658 | /// | ||||
3659 | /// Pragma intrisic tells the compiler to use a builtin version of the | ||||
3660 | /// function. Clang does it anyway, so the pragma doesn't really do anything. | ||||
3661 | /// Anyway, we emit a warning if the function specified in \#pragma intrinsic | ||||
3662 | /// isn't an intrinsic in clang and suggest to include intrin.h. | ||||
3663 | void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP, | ||||
3664 | PragmaIntroducer Introducer, | ||||
3665 | Token &Tok) { | ||||
3666 | PP.Lex(Tok); | ||||
3667 | |||||
3668 | if (Tok.isNot(tok::l_paren)) { | ||||
3669 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) | ||||
3670 | << "intrinsic"; | ||||
3671 | return; | ||||
3672 | } | ||||
3673 | PP.Lex(Tok); | ||||
3674 | |||||
3675 | bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); | ||||
3676 | |||||
3677 | while (Tok.is(tok::identifier)) { | ||||
3678 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3679 | if (!II->getBuiltinID()) | ||||
3680 | PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) | ||||
3681 | << II << SuggestIntrinH; | ||||
3682 | |||||
3683 | PP.Lex(Tok); | ||||
3684 | if (Tok.isNot(tok::comma)) | ||||
3685 | break; | ||||
3686 | PP.Lex(Tok); | ||||
3687 | } | ||||
3688 | |||||
3689 | if (Tok.isNot(tok::r_paren)) { | ||||
3690 | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | ||||
3691 | << "intrinsic"; | ||||
3692 | return; | ||||
3693 | } | ||||
3694 | PP.Lex(Tok); | ||||
3695 | |||||
3696 | if (Tok.isNot(tok::eod)) | ||||
3697 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3698 | << "intrinsic"; | ||||
3699 | } | ||||
3700 | |||||
3701 | bool Parser::HandlePragmaMSFunction(StringRef PragmaName, | ||||
3702 | SourceLocation PragmaLocation) { | ||||
3703 | Token FirstTok = Tok; | ||||
3704 | |||||
3705 | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | ||||
3706 | PragmaName)) | ||||
3707 | return false; | ||||
3708 | |||||
3709 | bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); | ||||
3710 | |||||
3711 | llvm::SmallVector<StringRef> NoBuiltins; | ||||
3712 | while (Tok.is(tok::identifier)) { | ||||
3713 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3714 | if (!II->getBuiltinID()) | ||||
3715 | PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) | ||||
3716 | << II << SuggestIntrinH; | ||||
3717 | else | ||||
3718 | NoBuiltins.emplace_back(II->getName()); | ||||
3719 | |||||
3720 | PP.Lex(Tok); | ||||
3721 | if (Tok.isNot(tok::comma)) | ||||
3722 | break; | ||||
3723 | PP.Lex(Tok); // , | ||||
3724 | } | ||||
3725 | |||||
3726 | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | ||||
3727 | PragmaName) || | ||||
3728 | ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | ||||
3729 | PragmaName)) | ||||
3730 | return false; | ||||
3731 | |||||
3732 | Actions.ActOnPragmaMSFunction(FirstTok.getLocation(), NoBuiltins); | ||||
3733 | return true; | ||||
3734 | } | ||||
3735 | |||||
3736 | // #pragma optimize("gsty", on|off) | ||||
3737 | bool Parser::HandlePragmaMSOptimize(StringRef PragmaName, | ||||
3738 | SourceLocation PragmaLocation) { | ||||
3739 | Token FirstTok = Tok; | ||||
3740 | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | ||||
3741 | PragmaName)) | ||||
3742 | return false; | ||||
3743 | |||||
3744 | if (Tok.isNot(tok::string_literal)) { | ||||
3745 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_string) << PragmaName; | ||||
3746 | return false; | ||||
3747 | } | ||||
3748 | ExprResult StringResult = ParseStringLiteralExpression(); | ||||
3749 | if (StringResult.isInvalid()) | ||||
3750 | return false; // Already diagnosed. | ||||
3751 | StringLiteral *OptimizationList = cast<StringLiteral>(StringResult.get()); | ||||
3752 | if (OptimizationList->getCharByteWidth() != 1) { | ||||
3753 | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | ||||
3754 | << PragmaName; | ||||
3755 | return false; | ||||
3756 | } | ||||
3757 | |||||
3758 | if (ExpectAndConsume(tok::comma, diag::warn_pragma_expected_comma, | ||||
3759 | PragmaName)) | ||||
3760 | return false; | ||||
3761 | |||||
3762 | if (Tok.is(tok::eof) || Tok.is(tok::r_paren)) { | ||||
3763 | PP.Diag(PragmaLocation, diag::warn_pragma_missing_argument) | ||||
3764 | << PragmaName << /*Expected=*/true << "'on' or 'off'"; | ||||
3765 | return false; | ||||
3766 | } | ||||
3767 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3768 | if (!II || (!II->isStr("on") && !II->isStr("off"))) { | ||||
3769 | PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument) | ||||
3770 | << PP.getSpelling(Tok) << PragmaName << /*Expected=*/true | ||||
3771 | << "'on' or 'off'"; | ||||
3772 | return false; | ||||
3773 | } | ||||
3774 | bool IsOn = II->isStr("on"); | ||||
3775 | PP.Lex(Tok); | ||||
3776 | |||||
3777 | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | ||||
3778 | PragmaName)) | ||||
3779 | return false; | ||||
3780 | |||||
3781 | // TODO: Add support for "sgty" | ||||
3782 | if (!OptimizationList->getString().empty()) { | ||||
3783 | PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument) | ||||
3784 | << OptimizationList->getString() << PragmaName << /*Expected=*/true | ||||
3785 | << "\"\""; | ||||
3786 | return false; | ||||
3787 | } | ||||
3788 | |||||
3789 | if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | ||||
3790 | PragmaName)) | ||||
3791 | return false; | ||||
3792 | |||||
3793 | Actions.ActOnPragmaMSOptimize(FirstTok.getLocation(), IsOn); | ||||
3794 | return true; | ||||
3795 | } | ||||
3796 | |||||
3797 | void PragmaForceCUDAHostDeviceHandler::HandlePragma( | ||||
3798 | Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) { | ||||
3799 | Token FirstTok = Tok; | ||||
3800 | |||||
3801 | PP.Lex(Tok); | ||||
3802 | IdentifierInfo *Info = Tok.getIdentifierInfo(); | ||||
3803 | if (!Info || (!Info->isStr("begin") && !Info->isStr("end"))) { | ||||
3804 | PP.Diag(FirstTok.getLocation(), | ||||
3805 | diag::warn_pragma_force_cuda_host_device_bad_arg); | ||||
3806 | return; | ||||
3807 | } | ||||
3808 | |||||
3809 | if (Info->isStr("begin")) | ||||
3810 | Actions.PushForceCUDAHostDevice(); | ||||
3811 | else if (!Actions.PopForceCUDAHostDevice()) | ||||
3812 | PP.Diag(FirstTok.getLocation(), | ||||
3813 | diag::err_pragma_cannot_end_force_cuda_host_device); | ||||
3814 | |||||
3815 | PP.Lex(Tok); | ||||
3816 | if (!Tok.is(tok::eod)) | ||||
3817 | PP.Diag(FirstTok.getLocation(), | ||||
3818 | diag::warn_pragma_force_cuda_host_device_bad_arg); | ||||
3819 | } | ||||
3820 | |||||
3821 | /// Handle the #pragma clang attribute directive. | ||||
3822 | /// | ||||
3823 | /// The syntax is: | ||||
3824 | /// \code | ||||
3825 | /// #pragma clang attribute push (attribute, subject-set) | ||||
3826 | /// #pragma clang attribute push | ||||
3827 | /// #pragma clang attribute (attribute, subject-set) | ||||
3828 | /// #pragma clang attribute pop | ||||
3829 | /// \endcode | ||||
3830 | /// | ||||
3831 | /// There are also 'namespace' variants of push and pop directives. The bare | ||||
3832 | /// '#pragma clang attribute (attribute, subject-set)' version doesn't require a | ||||
3833 | /// namespace, since it always applies attributes to the most recently pushed | ||||
3834 | /// group, regardless of namespace. | ||||
3835 | /// \code | ||||
3836 | /// #pragma clang attribute namespace.push (attribute, subject-set) | ||||
3837 | /// #pragma clang attribute namespace.push | ||||
3838 | /// #pragma clang attribute namespace.pop | ||||
3839 | /// \endcode | ||||
3840 | /// | ||||
3841 | /// The subject-set clause defines the set of declarations which receive the | ||||
3842 | /// attribute. Its exact syntax is described in the LanguageExtensions document | ||||
3843 | /// in Clang's documentation. | ||||
3844 | /// | ||||
3845 | /// This directive instructs the compiler to begin/finish applying the specified | ||||
3846 | /// attribute to the set of attribute-specific declarations in the active range | ||||
3847 | /// of the pragma. | ||||
3848 | void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, | ||||
3849 | PragmaIntroducer Introducer, | ||||
3850 | Token &FirstToken) { | ||||
3851 | Token Tok; | ||||
3852 | PP.Lex(Tok); | ||||
3853 | auto *Info = new (PP.getPreprocessorAllocator()) | ||||
3854 | PragmaAttributeInfo(AttributesForPragmaAttribute); | ||||
3855 | |||||
3856 | // Parse the optional namespace followed by a period. | ||||
3857 | if (Tok.is(tok::identifier)) { | ||||
3858 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3859 | if (!II->isStr("push") && !II->isStr("pop")) { | ||||
3860 | Info->Namespace = II; | ||||
3861 | PP.Lex(Tok); | ||||
3862 | |||||
3863 | if (!Tok.is(tok::period)) { | ||||
3864 | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_period) | ||||
3865 | << II; | ||||
3866 | return; | ||||
3867 | } | ||||
3868 | PP.Lex(Tok); | ||||
3869 | } | ||||
3870 | } | ||||
3871 | |||||
3872 | if (!Tok.isOneOf(tok::identifier, tok::l_paren)) { | ||||
3873 | PP.Diag(Tok.getLocation(), | ||||
3874 | diag::err_pragma_attribute_expected_push_pop_paren); | ||||
3875 | return; | ||||
3876 | } | ||||
3877 | |||||
3878 | // Determine what action this pragma clang attribute represents. | ||||
3879 | if (Tok.is(tok::l_paren)) { | ||||
3880 | if (Info->Namespace) { | ||||
3881 | PP.Diag(Tok.getLocation(), | ||||
3882 | diag::err_pragma_attribute_namespace_on_attribute); | ||||
3883 | PP.Diag(Tok.getLocation(), | ||||
3884 | diag::note_pragma_attribute_namespace_on_attribute); | ||||
3885 | return; | ||||
3886 | } | ||||
3887 | Info->Action = PragmaAttributeInfo::Attribute; | ||||
3888 | } else { | ||||
3889 | const IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
3890 | if (II->isStr("push")) | ||||
3891 | Info->Action = PragmaAttributeInfo::Push; | ||||
3892 | else if (II->isStr("pop")) | ||||
3893 | Info->Action = PragmaAttributeInfo::Pop; | ||||
3894 | else { | ||||
3895 | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument) | ||||
3896 | << PP.getSpelling(Tok); | ||||
3897 | return; | ||||
3898 | } | ||||
3899 | |||||
3900 | PP.Lex(Tok); | ||||
3901 | } | ||||
3902 | |||||
3903 | // Parse the actual attribute. | ||||
3904 | if ((Info->Action == PragmaAttributeInfo::Push && Tok.isNot(tok::eod)) || | ||||
3905 | Info->Action == PragmaAttributeInfo::Attribute) { | ||||
3906 | if (Tok.isNot(tok::l_paren)) { | ||||
3907 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | ||||
3908 | return; | ||||
3909 | } | ||||
3910 | PP.Lex(Tok); | ||||
3911 | |||||
3912 | // Lex the attribute tokens. | ||||
3913 | SmallVector<Token, 16> AttributeTokens; | ||||
3914 | int OpenParens = 1; | ||||
3915 | while (Tok.isNot(tok::eod)) { | ||||
3916 | if (Tok.is(tok::l_paren)) | ||||
3917 | OpenParens++; | ||||
3918 | else if (Tok.is(tok::r_paren)) { | ||||
3919 | OpenParens--; | ||||
3920 | if (OpenParens == 0) | ||||
3921 | break; | ||||
3922 | } | ||||
3923 | |||||
3924 | AttributeTokens.push_back(Tok); | ||||
3925 | PP.Lex(Tok); | ||||
3926 | } | ||||
3927 | |||||
3928 | if (AttributeTokens.empty()) { | ||||
3929 | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute); | ||||
3930 | return; | ||||
3931 | } | ||||
3932 | if (Tok.isNot(tok::r_paren)) { | ||||
3933 | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | ||||
3934 | return; | ||||
3935 | } | ||||
3936 | SourceLocation EndLoc = Tok.getLocation(); | ||||
3937 | PP.Lex(Tok); | ||||
3938 | |||||
3939 | // Terminate the attribute for parsing. | ||||
3940 | Token EOFTok; | ||||
3941 | EOFTok.startToken(); | ||||
3942 | EOFTok.setKind(tok::eof); | ||||
3943 | EOFTok.setLocation(EndLoc); | ||||
3944 | AttributeTokens.push_back(EOFTok); | ||||
3945 | |||||
3946 | markAsReinjectedForRelexing(AttributeTokens); | ||||
3947 | Info->Tokens = | ||||
3948 | llvm::ArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator()); | ||||
3949 | } | ||||
3950 | |||||
3951 | if (Tok.isNot(tok::eod)) | ||||
3952 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3953 | << "clang attribute"; | ||||
3954 | |||||
3955 | // Generate the annotated pragma token. | ||||
3956 | auto TokenArray = std::make_unique<Token[]>(1); | ||||
3957 | TokenArray[0].startToken(); | ||||
3958 | TokenArray[0].setKind(tok::annot_pragma_attribute); | ||||
3959 | TokenArray[0].setLocation(FirstToken.getLocation()); | ||||
3960 | TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation()); | ||||
3961 | TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); | ||||
3962 | PP.EnterTokenStream(std::move(TokenArray), 1, | ||||
3963 | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | ||||
3964 | } | ||||
3965 | |||||
3966 | // Handle '#pragma clang max_tokens 12345'. | ||||
3967 | void PragmaMaxTokensHereHandler::HandlePragma(Preprocessor &PP, | ||||
3968 | PragmaIntroducer Introducer, | ||||
3969 | Token &Tok) { | ||||
3970 | PP.Lex(Tok); | ||||
3971 | if (Tok.is(tok::eod)) { | ||||
3972 | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | ||||
3973 | << "clang max_tokens_here" << /*Expected=*/true << "integer"; | ||||
3974 | return; | ||||
3975 | } | ||||
3976 | |||||
3977 | SourceLocation Loc = Tok.getLocation(); | ||||
3978 | uint64_t MaxTokens; | ||||
3979 | if (Tok.isNot(tok::numeric_constant) || | ||||
3980 | !PP.parseSimpleIntegerLiteral(Tok, MaxTokens)) { | ||||
3981 | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_integer) | ||||
3982 | << "clang max_tokens_here"; | ||||
3983 | return; | ||||
3984 | } | ||||
3985 | |||||
3986 | if (Tok.isNot(tok::eod)) { | ||||
3987 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
3988 | << "clang max_tokens_here"; | ||||
3989 | return; | ||||
3990 | } | ||||
3991 | |||||
3992 | if (PP.getTokenCount() > MaxTokens) { | ||||
3993 | PP.Diag(Loc, diag::warn_max_tokens) | ||||
3994 | << PP.getTokenCount() << (unsigned)MaxTokens; | ||||
3995 | } | ||||
3996 | } | ||||
3997 | |||||
3998 | // Handle '#pragma clang max_tokens_total 12345'. | ||||
3999 | void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP, | ||||
4000 | PragmaIntroducer Introducer, | ||||
4001 | Token &Tok) { | ||||
4002 | PP.Lex(Tok); | ||||
4003 | if (Tok.is(tok::eod)) { | ||||
4004 | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | ||||
4005 | << "clang max_tokens_total" << /*Expected=*/true << "integer"; | ||||
4006 | return; | ||||
4007 | } | ||||
4008 | |||||
4009 | SourceLocation Loc = Tok.getLocation(); | ||||
4010 | uint64_t MaxTokens; | ||||
4011 | if (Tok.isNot(tok::numeric_constant) || | ||||
4012 | !PP.parseSimpleIntegerLiteral(Tok, MaxTokens)) { | ||||
4013 | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_integer) | ||||
4014 | << "clang max_tokens_total"; | ||||
4015 | return; | ||||
4016 | } | ||||
4017 | |||||
4018 | if (Tok.isNot(tok::eod)) { | ||||
4019 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
4020 | << "clang max_tokens_total"; | ||||
4021 | return; | ||||
4022 | } | ||||
4023 | |||||
4024 | PP.overrideMaxTokens(MaxTokens, Loc); | ||||
4025 | } | ||||
4026 | |||||
4027 | // Handle '#pragma clang riscv intrinsic vector'. | ||||
4028 | // '#pragma clang riscv intrinsic sifive_vector'. | ||||
4029 | void PragmaRISCVHandler::HandlePragma(Preprocessor &PP, | ||||
4030 | PragmaIntroducer Introducer, | ||||
4031 | Token &FirstToken) { | ||||
4032 | Token Tok; | ||||
4033 | PP.Lex(Tok); | ||||
4034 | IdentifierInfo *II = Tok.getIdentifierInfo(); | ||||
4035 | |||||
4036 | if (!II || !II->isStr("intrinsic")) { | ||||
4037 | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument) | ||||
4038 | << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'"; | ||||
4039 | return; | ||||
4040 | } | ||||
4041 | |||||
4042 | PP.Lex(Tok); | ||||
4043 | II = Tok.getIdentifierInfo(); | ||||
4044 | StringRef IntrinsicClass = II->getName(); | ||||
4045 | if (!II || !(II->isStr("vector") || II->isStr("sifive_vector"))) { | ||||
4046 | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument) | ||||
4047 | << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true | ||||
4048 | << "'vector' or 'sifive_vector'"; | ||||
4049 | return; | ||||
4050 | } | ||||
4051 | |||||
4052 | PP.Lex(Tok); | ||||
4053 | if (Tok.isNot(tok::eod)) { | ||||
4054 | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||||
4055 | << "clang riscv intrinsic"; | ||||
4056 | return; | ||||
4057 | } | ||||
4058 | |||||
4059 | if (IntrinsicClass == "vector") | ||||
4060 | Actions.DeclareRISCVVBuiltins = true; | ||||
4061 | else if (IntrinsicClass == "sifive_vector") | ||||
4062 | Actions.DeclareRISCVVectorBuiltins = true; | ||||
4063 | } |
1 | //===- Diagnostic.h - C Language Family Diagnostic Handling -----*- C++ -*-===// | ||||
2 | // | ||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
6 | // | ||||
7 | //===----------------------------------------------------------------------===// | ||||
8 | // | ||||
9 | /// \file | ||||
10 | /// Defines the Diagnostic-related interfaces. | ||||
11 | // | ||||
12 | //===----------------------------------------------------------------------===// | ||||
13 | |||||
14 | #ifndef LLVM_CLANG_BASIC_DIAGNOSTIC_H | ||||
15 | #define LLVM_CLANG_BASIC_DIAGNOSTIC_H | ||||
16 | |||||
17 | #include "clang/Basic/DiagnosticIDs.h" | ||||
18 | #include "clang/Basic/DiagnosticOptions.h" | ||||
19 | #include "clang/Basic/SourceLocation.h" | ||||
20 | #include "clang/Basic/Specifiers.h" | ||||
21 | #include "llvm/ADT/ArrayRef.h" | ||||
22 | #include "llvm/ADT/DenseMap.h" | ||||
23 | #include "llvm/ADT/IntrusiveRefCntPtr.h" | ||||
24 | #include "llvm/ADT/SmallVector.h" | ||||
25 | #include "llvm/ADT/StringRef.h" | ||||
26 | #include "llvm/ADT/iterator_range.h" | ||||
27 | #include "llvm/Support/Compiler.h" | ||||
28 | #include <cassert> | ||||
29 | #include <cstdint> | ||||
30 | #include <limits> | ||||
31 | #include <list> | ||||
32 | #include <map> | ||||
33 | #include <memory> | ||||
34 | #include <optional> | ||||
35 | #include <string> | ||||
36 | #include <type_traits> | ||||
37 | #include <utility> | ||||
38 | #include <vector> | ||||
39 | |||||
40 | namespace llvm { | ||||
41 | class Error; | ||||
42 | class raw_ostream; | ||||
43 | } // namespace llvm | ||||
44 | |||||
45 | namespace clang { | ||||
46 | |||||
47 | class DeclContext; | ||||
48 | class DiagnosticBuilder; | ||||
49 | class DiagnosticConsumer; | ||||
50 | class IdentifierInfo; | ||||
51 | class LangOptions; | ||||
52 | class Preprocessor; | ||||
53 | class SourceManager; | ||||
54 | class StoredDiagnostic; | ||||
55 | |||||
56 | namespace tok { | ||||
57 | |||||
58 | enum TokenKind : unsigned short; | ||||
59 | |||||
60 | } // namespace tok | ||||
61 | |||||
62 | /// Annotates a diagnostic with some code that should be | ||||
63 | /// inserted, removed, or replaced to fix the problem. | ||||
64 | /// | ||||
65 | /// This kind of hint should be used when we are certain that the | ||||
66 | /// introduction, removal, or modification of a particular (small!) | ||||
67 | /// amount of code will correct a compilation error. The compiler | ||||
68 | /// should also provide full recovery from such errors, such that | ||||
69 | /// suppressing the diagnostic output can still result in successful | ||||
70 | /// compilation. | ||||
71 | class FixItHint { | ||||
72 | public: | ||||
73 | /// Code that should be replaced to correct the error. Empty for an | ||||
74 | /// insertion hint. | ||||
75 | CharSourceRange RemoveRange; | ||||
76 | |||||
77 | /// Code in the specific range that should be inserted in the insertion | ||||
78 | /// location. | ||||
79 | CharSourceRange InsertFromRange; | ||||
80 | |||||
81 | /// The actual code to insert at the insertion location, as a | ||||
82 | /// string. | ||||
83 | std::string CodeToInsert; | ||||
84 | |||||
85 | bool BeforePreviousInsertions = false; | ||||
86 | |||||
87 | /// Empty code modification hint, indicating that no code | ||||
88 | /// modification is known. | ||||
89 | FixItHint() = default; | ||||
90 | |||||
91 | bool isNull() const { | ||||
92 | return !RemoveRange.isValid(); | ||||
93 | } | ||||
94 | |||||
95 | /// Create a code modification hint that inserts the given | ||||
96 | /// code string at a specific location. | ||||
97 | static FixItHint CreateInsertion(SourceLocation InsertionLoc, | ||||
98 | StringRef Code, | ||||
99 | bool BeforePreviousInsertions = false) { | ||||
100 | FixItHint Hint; | ||||
101 | Hint.RemoveRange = | ||||
102 | CharSourceRange::getCharRange(InsertionLoc, InsertionLoc); | ||||
103 | Hint.CodeToInsert = std::string(Code); | ||||
104 | Hint.BeforePreviousInsertions = BeforePreviousInsertions; | ||||
105 | return Hint; | ||||
106 | } | ||||
107 | |||||
108 | /// Create a code modification hint that inserts the given | ||||
109 | /// code from \p FromRange at a specific location. | ||||
110 | static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, | ||||
111 | CharSourceRange FromRange, | ||||
112 | bool BeforePreviousInsertions = false) { | ||||
113 | FixItHint Hint; | ||||
114 | Hint.RemoveRange = | ||||
115 | CharSourceRange::getCharRange(InsertionLoc, InsertionLoc); | ||||
116 | Hint.InsertFromRange = FromRange; | ||||
117 | Hint.BeforePreviousInsertions = BeforePreviousInsertions; | ||||
118 | return Hint; | ||||
119 | } | ||||
120 | |||||
121 | /// Create a code modification hint that removes the given | ||||
122 | /// source range. | ||||
123 | static FixItHint CreateRemoval(CharSourceRange RemoveRange) { | ||||
124 | FixItHint Hint; | ||||
125 | Hint.RemoveRange = RemoveRange; | ||||
126 | return Hint; | ||||
127 | } | ||||
128 | static FixItHint CreateRemoval(SourceRange RemoveRange) { | ||||
129 | return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange)); | ||||
130 | } | ||||
131 | |||||
132 | /// Create a code modification hint that replaces the given | ||||
133 | /// source range with the given code string. | ||||
134 | static FixItHint CreateReplacement(CharSourceRange RemoveRange, | ||||
135 | StringRef Code) { | ||||
136 | FixItHint Hint; | ||||
137 | Hint.RemoveRange = RemoveRange; | ||||
138 | Hint.CodeToInsert = std::string(Code); | ||||
139 | return Hint; | ||||
140 | } | ||||
141 | |||||
142 | static FixItHint CreateReplacement(SourceRange RemoveRange, | ||||
143 | StringRef Code) { | ||||
144 | return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code); | ||||
145 | } | ||||
146 | }; | ||||
147 | |||||
148 | struct DiagnosticStorage { | ||||
149 | enum { | ||||
150 | /// The maximum number of arguments we can hold. We | ||||
151 | /// currently only support up to 10 arguments (%0-%9). | ||||
152 | /// | ||||
153 | /// A single diagnostic with more than that almost certainly has to | ||||
154 | /// be simplified anyway. | ||||
155 | MaxArguments = 10 | ||||
156 | }; | ||||
157 | |||||
158 | /// The number of entries in Arguments. | ||||
159 | unsigned char NumDiagArgs = 0; | ||||
160 | |||||
161 | /// Specifies for each argument whether it is in DiagArgumentsStr | ||||
162 | /// or in DiagArguments. | ||||
163 | unsigned char DiagArgumentsKind[MaxArguments]; | ||||
164 | |||||
165 | /// The values for the various substitution positions. | ||||
166 | /// | ||||
167 | /// This is used when the argument is not an std::string. The specific value | ||||
168 | /// is mangled into an uint64_t and the interpretation depends on exactly | ||||
169 | /// what sort of argument kind it is. | ||||
170 | uint64_t DiagArgumentsVal[MaxArguments]; | ||||
171 | |||||
172 | /// The values for the various substitution positions that have | ||||
173 | /// string arguments. | ||||
174 | std::string DiagArgumentsStr[MaxArguments]; | ||||
175 | |||||
176 | /// The list of ranges added to this diagnostic. | ||||
177 | SmallVector<CharSourceRange, 8> DiagRanges; | ||||
178 | |||||
179 | /// If valid, provides a hint with some code to insert, remove, or | ||||
180 | /// modify at a particular position. | ||||
181 | SmallVector<FixItHint, 6> FixItHints; | ||||
182 | |||||
183 | DiagnosticStorage() = default; | ||||
184 | }; | ||||
185 | |||||
186 | /// Concrete class used by the front-end to report problems and issues. | ||||
187 | /// | ||||
188 | /// This massages the diagnostics (e.g. handling things like "report warnings | ||||
189 | /// as errors" and passes them off to the DiagnosticConsumer for reporting to | ||||
190 | /// the user. DiagnosticsEngine is tied to one translation unit and one | ||||
191 | /// SourceManager. | ||||
192 | class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { | ||||
193 | public: | ||||
194 | /// The level of the diagnostic, after it has been through mapping. | ||||
195 | enum Level { | ||||
196 | Ignored = DiagnosticIDs::Ignored, | ||||
197 | Note = DiagnosticIDs::Note, | ||||
198 | Remark = DiagnosticIDs::Remark, | ||||
199 | Warning = DiagnosticIDs::Warning, | ||||
200 | Error = DiagnosticIDs::Error, | ||||
201 | Fatal = DiagnosticIDs::Fatal | ||||
202 | }; | ||||
203 | |||||
204 | enum ArgumentKind { | ||||
205 | /// std::string | ||||
206 | ak_std_string, | ||||
207 | |||||
208 | /// const char * | ||||
209 | ak_c_string, | ||||
210 | |||||
211 | /// int | ||||
212 | ak_sint, | ||||
213 | |||||
214 | /// unsigned | ||||
215 | ak_uint, | ||||
216 | |||||
217 | /// enum TokenKind : unsigned | ||||
218 | ak_tokenkind, | ||||
219 | |||||
220 | /// IdentifierInfo | ||||
221 | ak_identifierinfo, | ||||
222 | |||||
223 | /// address space | ||||
224 | ak_addrspace, | ||||
225 | |||||
226 | /// Qualifiers | ||||
227 | ak_qual, | ||||
228 | |||||
229 | /// QualType | ||||
230 | ak_qualtype, | ||||
231 | |||||
232 | /// DeclarationName | ||||
233 | ak_declarationname, | ||||
234 | |||||
235 | /// NamedDecl * | ||||
236 | ak_nameddecl, | ||||
237 | |||||
238 | /// NestedNameSpecifier * | ||||
239 | ak_nestednamespec, | ||||
240 | |||||
241 | /// DeclContext * | ||||
242 | ak_declcontext, | ||||
243 | |||||
244 | /// pair<QualType, QualType> | ||||
245 | ak_qualtype_pair, | ||||
246 | |||||
247 | /// Attr * | ||||
248 | ak_attr | ||||
249 | }; | ||||
250 | |||||
251 | /// Represents on argument value, which is a union discriminated | ||||
252 | /// by ArgumentKind, with a value. | ||||
253 | using ArgumentValue = std::pair<ArgumentKind, intptr_t>; | ||||
254 | |||||
255 | private: | ||||
256 | // Used by __extension__ | ||||
257 | unsigned char AllExtensionsSilenced = 0; | ||||
258 | |||||
259 | // Treat fatal errors like errors. | ||||
260 | bool FatalsAsError = false; | ||||
261 | |||||
262 | // Suppress all diagnostics. | ||||
263 | bool SuppressAllDiagnostics = false; | ||||
264 | |||||
265 | // Elide common types of templates. | ||||
266 | bool ElideType = true; | ||||
267 | |||||
268 | // Print a tree when comparing templates. | ||||
269 | bool PrintTemplateTree = false; | ||||
270 | |||||
271 | // Color printing is enabled. | ||||
272 | bool ShowColors = false; | ||||
273 | |||||
274 | // Which overload candidates to show. | ||||
275 | OverloadsShown ShowOverloads = Ovl_All; | ||||
276 | |||||
277 | // With Ovl_Best, the number of overload candidates to show when we encounter | ||||
278 | // an error. | ||||
279 | // | ||||
280 | // The value here is the number of candidates to show in the first nontrivial | ||||
281 | // error. Future errors may show a different number of candidates. | ||||
282 | unsigned NumOverloadsToShow = 32; | ||||
283 | |||||
284 | // Cap of # errors emitted, 0 -> no limit. | ||||
285 | unsigned ErrorLimit = 0; | ||||
286 | |||||
287 | // Cap on depth of template backtrace stack, 0 -> no limit. | ||||
288 | unsigned TemplateBacktraceLimit = 0; | ||||
289 | |||||
290 | // Cap on depth of constexpr evaluation backtrace stack, 0 -> no limit. | ||||
291 | unsigned ConstexprBacktraceLimit = 0; | ||||
292 | |||||
293 | IntrusiveRefCntPtr<DiagnosticIDs> Diags; | ||||
294 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; | ||||
295 | DiagnosticConsumer *Client = nullptr; | ||||
296 | std::unique_ptr<DiagnosticConsumer> Owner; | ||||
297 | SourceManager *SourceMgr = nullptr; | ||||
298 | |||||
299 | /// Mapping information for diagnostics. | ||||
300 | /// | ||||
301 | /// Mapping info is packed into four bits per diagnostic. The low three | ||||
302 | /// bits are the mapping (an instance of diag::Severity), or zero if unset. | ||||
303 | /// The high bit is set when the mapping was established as a user mapping. | ||||
304 | /// If the high bit is clear, then the low bits are set to the default | ||||
305 | /// value, and should be mapped with -pedantic, -Werror, etc. | ||||
306 | /// | ||||
307 | /// A new DiagState is created and kept around when diagnostic pragmas modify | ||||
308 | /// the state so that we know what is the diagnostic state at any given | ||||
309 | /// source location. | ||||
310 | class DiagState { | ||||
311 | llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap; | ||||
312 | |||||
313 | public: | ||||
314 | // "Global" configuration state that can actually vary between modules. | ||||
315 | |||||
316 | // Ignore all warnings: -w | ||||
317 | unsigned IgnoreAllWarnings : 1; | ||||
318 | |||||
319 | // Enable all warnings. | ||||
320 | unsigned EnableAllWarnings : 1; | ||||
321 | |||||
322 | // Treat warnings like errors. | ||||
323 | unsigned WarningsAsErrors : 1; | ||||
324 | |||||
325 | // Treat errors like fatal errors. | ||||
326 | unsigned ErrorsAsFatal : 1; | ||||
327 | |||||
328 | // Suppress warnings in system headers. | ||||
329 | unsigned SuppressSystemWarnings : 1; | ||||
330 | |||||
331 | // Map extensions to warnings or errors? | ||||
332 | diag::Severity ExtBehavior = diag::Severity::Ignored; | ||||
333 | |||||
334 | DiagState() | ||||
335 | : IgnoreAllWarnings(false), EnableAllWarnings(false), | ||||
336 | WarningsAsErrors(false), ErrorsAsFatal(false), | ||||
337 | SuppressSystemWarnings(false) {} | ||||
338 | |||||
339 | using iterator = llvm::DenseMap<unsigned, DiagnosticMapping>::iterator; | ||||
340 | using const_iterator = | ||||
341 | llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator; | ||||
342 | |||||
343 | void setMapping(diag::kind Diag, DiagnosticMapping Info) { | ||||
344 | DiagMap[Diag] = Info; | ||||
345 | } | ||||
346 | |||||
347 | DiagnosticMapping lookupMapping(diag::kind Diag) const { | ||||
348 | return DiagMap.lookup(Diag); | ||||
349 | } | ||||
350 | |||||
351 | DiagnosticMapping &getOrAddMapping(diag::kind Diag); | ||||
352 | |||||
353 | const_iterator begin() const { return DiagMap.begin(); } | ||||
354 | const_iterator end() const { return DiagMap.end(); } | ||||
355 | }; | ||||
356 | |||||
357 | /// Keeps and automatically disposes all DiagStates that we create. | ||||
358 | std::list<DiagState> DiagStates; | ||||
359 | |||||
360 | /// A mapping from files to the diagnostic states for those files. Lazily | ||||
361 | /// built on demand for files in which the diagnostic state has not changed. | ||||
362 | class DiagStateMap { | ||||
363 | public: | ||||
364 | /// Add an initial diagnostic state. | ||||
365 | void appendFirst(DiagState *State); | ||||
366 | |||||
367 | /// Add a new latest state point. | ||||
368 | void append(SourceManager &SrcMgr, SourceLocation Loc, DiagState *State); | ||||
369 | |||||
370 | /// Look up the diagnostic state at a given source location. | ||||
371 | DiagState *lookup(SourceManager &SrcMgr, SourceLocation Loc) const; | ||||
372 | |||||
373 | /// Determine whether this map is empty. | ||||
374 | bool empty() const { return Files.empty(); } | ||||
375 | |||||
376 | /// Clear out this map. | ||||
377 | void clear() { | ||||
378 | Files.clear(); | ||||
379 | FirstDiagState = CurDiagState = nullptr; | ||||
380 | CurDiagStateLoc = SourceLocation(); | ||||
381 | } | ||||
382 | |||||
383 | /// Produce a debugging dump of the diagnostic state. | ||||
384 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump(SourceManager &SrcMgr, | ||||
385 | StringRef DiagName = StringRef()) const; | ||||
386 | |||||
387 | /// Grab the most-recently-added state point. | ||||
388 | DiagState *getCurDiagState() const { return CurDiagState; } | ||||
389 | |||||
390 | /// Get the location at which a diagnostic state was last added. | ||||
391 | SourceLocation getCurDiagStateLoc() const { return CurDiagStateLoc; } | ||||
392 | |||||
393 | private: | ||||
394 | friend class ASTReader; | ||||
395 | friend class ASTWriter; | ||||
396 | |||||
397 | /// Represents a point in source where the diagnostic state was | ||||
398 | /// modified because of a pragma. | ||||
399 | /// | ||||
400 | /// 'Loc' can be null if the point represents the diagnostic state | ||||
401 | /// modifications done through the command-line. | ||||
402 | struct DiagStatePoint { | ||||
403 | DiagState *State; | ||||
404 | unsigned Offset; | ||||
405 | |||||
406 | DiagStatePoint(DiagState *State, unsigned Offset) | ||||
407 | : State(State), Offset(Offset) {} | ||||
408 | }; | ||||
409 | |||||
410 | /// Description of the diagnostic states and state transitions for a | ||||
411 | /// particular FileID. | ||||
412 | struct File { | ||||
413 | /// The diagnostic state for the parent file. This is strictly redundant, | ||||
414 | /// as looking up the DecomposedIncludedLoc for the FileID in the Files | ||||
415 | /// map would give us this, but we cache it here for performance. | ||||
416 | File *Parent = nullptr; | ||||
417 | |||||
418 | /// The offset of this file within its parent. | ||||
419 | unsigned ParentOffset = 0; | ||||
420 | |||||
421 | /// Whether this file has any local (not imported from an AST file) | ||||
422 | /// diagnostic state transitions. | ||||
423 | bool HasLocalTransitions = false; | ||||
424 | |||||
425 | /// The points within the file where the state changes. There will always | ||||
426 | /// be at least one of these (the state on entry to the file). | ||||
427 | llvm::SmallVector<DiagStatePoint, 4> StateTransitions; | ||||
428 | |||||
429 | DiagState *lookup(unsigned Offset) const; | ||||
430 | }; | ||||
431 | |||||
432 | /// The diagnostic states for each file. | ||||
433 | mutable std::map<FileID, File> Files; | ||||
434 | |||||
435 | /// The initial diagnostic state. | ||||
436 | DiagState *FirstDiagState; | ||||
437 | |||||
438 | /// The current diagnostic state. | ||||
439 | DiagState *CurDiagState; | ||||
440 | |||||
441 | /// The location at which the current diagnostic state was established. | ||||
442 | SourceLocation CurDiagStateLoc; | ||||
443 | |||||
444 | /// Get the diagnostic state information for a file. | ||||
445 | File *getFile(SourceManager &SrcMgr, FileID ID) const; | ||||
446 | }; | ||||
447 | |||||
448 | DiagStateMap DiagStatesByLoc; | ||||
449 | |||||
450 | /// Keeps the DiagState that was active during each diagnostic 'push' | ||||
451 | /// so we can get back at it when we 'pop'. | ||||
452 | std::vector<DiagState *> DiagStateOnPushStack; | ||||
453 | |||||
454 | DiagState *GetCurDiagState() const { | ||||
455 | return DiagStatesByLoc.getCurDiagState(); | ||||
456 | } | ||||
457 | |||||
458 | void PushDiagStatePoint(DiagState *State, SourceLocation L); | ||||
459 | |||||
460 | /// Finds the DiagStatePoint that contains the diagnostic state of | ||||
461 | /// the given source location. | ||||
462 | DiagState *GetDiagStateForLoc(SourceLocation Loc) const { | ||||
463 | return SourceMgr ? DiagStatesByLoc.lookup(*SourceMgr, Loc) | ||||
464 | : DiagStatesByLoc.getCurDiagState(); | ||||
465 | } | ||||
466 | |||||
467 | /// Sticky flag set to \c true when an error is emitted. | ||||
468 | bool ErrorOccurred; | ||||
469 | |||||
470 | /// Sticky flag set to \c true when an "uncompilable error" occurs. | ||||
471 | /// I.e. an error that was not upgraded from a warning by -Werror. | ||||
472 | bool UncompilableErrorOccurred; | ||||
473 | |||||
474 | /// Sticky flag set to \c true when a fatal error is emitted. | ||||
475 | bool FatalErrorOccurred; | ||||
476 | |||||
477 | /// Indicates that an unrecoverable error has occurred. | ||||
478 | bool UnrecoverableErrorOccurred; | ||||
479 | |||||
480 | /// Counts for DiagnosticErrorTrap to check whether an error occurred | ||||
481 | /// during a parsing section, e.g. during parsing a function. | ||||
482 | unsigned TrapNumErrorsOccurred; | ||||
483 | unsigned TrapNumUnrecoverableErrorsOccurred; | ||||
484 | |||||
485 | /// The level of the last diagnostic emitted. | ||||
486 | /// | ||||
487 | /// This is used to emit continuation diagnostics with the same level as the | ||||
488 | /// diagnostic that they follow. | ||||
489 | DiagnosticIDs::Level LastDiagLevel; | ||||
490 | |||||
491 | /// Number of warnings reported | ||||
492 | unsigned NumWarnings; | ||||
493 | |||||
494 | /// Number of errors reported | ||||
495 | unsigned NumErrors; | ||||
496 | |||||
497 | /// A function pointer that converts an opaque diagnostic | ||||
498 | /// argument to a strings. | ||||
499 | /// | ||||
500 | /// This takes the modifiers and argument that was present in the diagnostic. | ||||
501 | /// | ||||
502 | /// The PrevArgs array indicates the previous arguments formatted for this | ||||
503 | /// diagnostic. Implementations of this function can use this information to | ||||
504 | /// avoid redundancy across arguments. | ||||
505 | /// | ||||
506 | /// This is a hack to avoid a layering violation between libbasic and libsema. | ||||
507 | using ArgToStringFnTy = void (*)( | ||||
508 | ArgumentKind Kind, intptr_t Val, | ||||
509 | StringRef Modifier, StringRef Argument, | ||||
510 | ArrayRef<ArgumentValue> PrevArgs, | ||||
511 | SmallVectorImpl<char> &Output, | ||||
512 | void *Cookie, | ||||
513 | ArrayRef<intptr_t> QualTypeVals); | ||||
514 | |||||
515 | void *ArgToStringCookie = nullptr; | ||||
516 | ArgToStringFnTy ArgToStringFn; | ||||
517 | |||||
518 | /// ID of the "delayed" diagnostic, which is a (typically | ||||
519 | /// fatal) diagnostic that had to be delayed because it was found | ||||
520 | /// while emitting another diagnostic. | ||||
521 | unsigned DelayedDiagID; | ||||
522 | |||||
523 | /// First string argument for the delayed diagnostic. | ||||
524 | std::string DelayedDiagArg1; | ||||
525 | |||||
526 | /// Second string argument for the delayed diagnostic. | ||||
527 | std::string DelayedDiagArg2; | ||||
528 | |||||
529 | /// Third string argument for the delayed diagnostic. | ||||
530 | std::string DelayedDiagArg3; | ||||
531 | |||||
532 | /// Optional flag value. | ||||
533 | /// | ||||
534 | /// Some flags accept values, for instance: -Wframe-larger-than=<value> and | ||||
535 | /// -Rpass=<value>. The content of this string is emitted after the flag name | ||||
536 | /// and '='. | ||||
537 | std::string FlagValue; | ||||
538 | |||||
539 | public: | ||||
540 | explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags, | ||||
541 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, | ||||
542 | DiagnosticConsumer *client = nullptr, | ||||
543 | bool ShouldOwnClient = true); | ||||
544 | DiagnosticsEngine(const DiagnosticsEngine &) = delete; | ||||
545 | DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete; | ||||
546 | ~DiagnosticsEngine(); | ||||
547 | |||||
548 | friend void DiagnosticsTestHelper(DiagnosticsEngine &); | ||||
549 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump() const; | ||||
550 | LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump(StringRef DiagName) const; | ||||
551 | |||||
552 | const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { | ||||
553 | return Diags; | ||||
554 | } | ||||
555 | |||||
556 | /// Retrieve the diagnostic options. | ||||
557 | DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; } | ||||
558 | |||||
559 | using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>; | ||||
560 | |||||
561 | /// Get the current set of diagnostic mappings. | ||||
562 | diag_mapping_range getDiagnosticMappings() const { | ||||
563 | const DiagState &DS = *GetCurDiagState(); | ||||
564 | return diag_mapping_range(DS.begin(), DS.end()); | ||||
565 | } | ||||
566 | |||||
567 | DiagnosticConsumer *getClient() { return Client; } | ||||
568 | const DiagnosticConsumer *getClient() const { return Client; } | ||||
569 | |||||
570 | /// Determine whether this \c DiagnosticsEngine object own its client. | ||||
571 | bool ownsClient() const { return Owner != nullptr; } | ||||
572 | |||||
573 | /// Return the current diagnostic client along with ownership of that | ||||
574 | /// client. | ||||
575 | std::unique_ptr<DiagnosticConsumer> takeClient() { return std::move(Owner); } | ||||
576 | |||||
577 | bool hasSourceManager() const { return SourceMgr != nullptr; } | ||||
578 | |||||
579 | SourceManager &getSourceManager() const { | ||||
580 | assert(SourceMgr && "SourceManager not set!")(static_cast <bool> (SourceMgr && "SourceManager not set!" ) ? void (0) : __assert_fail ("SourceMgr && \"SourceManager not set!\"" , "clang/include/clang/Basic/Diagnostic.h", 580, __extension__ __PRETTY_FUNCTION__)); | ||||
581 | return *SourceMgr; | ||||
582 | } | ||||
583 | |||||
584 | void setSourceManager(SourceManager *SrcMgr) { | ||||
585 | assert(DiagStatesByLoc.empty() &&(static_cast <bool> (DiagStatesByLoc.empty() && "Leftover diag state from a different SourceManager.") ? void (0) : __assert_fail ("DiagStatesByLoc.empty() && \"Leftover diag state from a different SourceManager.\"" , "clang/include/clang/Basic/Diagnostic.h", 586, __extension__ __PRETTY_FUNCTION__)) | ||||
586 | "Leftover diag state from a different SourceManager.")(static_cast <bool> (DiagStatesByLoc.empty() && "Leftover diag state from a different SourceManager.") ? void (0) : __assert_fail ("DiagStatesByLoc.empty() && \"Leftover diag state from a different SourceManager.\"" , "clang/include/clang/Basic/Diagnostic.h", 586, __extension__ __PRETTY_FUNCTION__)); | ||||
587 | SourceMgr = SrcMgr; | ||||
588 | } | ||||
589 | |||||
590 | //===--------------------------------------------------------------------===// | ||||
591 | // DiagnosticsEngine characterization methods, used by a client to customize | ||||
592 | // how diagnostics are emitted. | ||||
593 | // | ||||
594 | |||||
595 | /// Copies the current DiagMappings and pushes the new copy | ||||
596 | /// onto the top of the stack. | ||||
597 | void pushMappings(SourceLocation Loc); | ||||
598 | |||||
599 | /// Pops the current DiagMappings off the top of the stack, | ||||
600 | /// causing the new top of the stack to be the active mappings. | ||||
601 | /// | ||||
602 | /// \returns \c true if the pop happens, \c false if there is only one | ||||
603 | /// DiagMapping on the stack. | ||||
604 | bool popMappings(SourceLocation Loc); | ||||
605 | |||||
606 | /// Set the diagnostic client associated with this diagnostic object. | ||||
607 | /// | ||||
608 | /// \param ShouldOwnClient true if the diagnostic object should take | ||||
609 | /// ownership of \c client. | ||||
610 | void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true); | ||||
611 | |||||
612 | /// Specify a limit for the number of errors we should | ||||
613 | /// emit before giving up. | ||||
614 | /// | ||||
615 | /// Zero disables the limit. | ||||
616 | void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; } | ||||
617 | |||||
618 | /// Specify the maximum number of template instantiation | ||||
619 | /// notes to emit along with a given diagnostic. | ||||
620 | void setTemplateBacktraceLimit(unsigned Limit) { | ||||
621 | TemplateBacktraceLimit = Limit; | ||||
622 | } | ||||
623 | |||||
624 | /// Retrieve the maximum number of template instantiation | ||||
625 | /// notes to emit along with a given diagnostic. | ||||
626 | unsigned getTemplateBacktraceLimit() const { | ||||
627 | return TemplateBacktraceLimit; | ||||
628 | } | ||||
629 | |||||
630 | /// Specify the maximum number of constexpr evaluation | ||||
631 | /// notes to emit along with a given diagnostic. | ||||
632 | void setConstexprBacktraceLimit(unsigned Limit) { | ||||
633 | ConstexprBacktraceLimit = Limit; | ||||
634 | } | ||||
635 | |||||
636 | /// Retrieve the maximum number of constexpr evaluation | ||||
637 | /// notes to emit along with a given diagnostic. | ||||
638 | unsigned getConstexprBacktraceLimit() const { | ||||
639 | return ConstexprBacktraceLimit; | ||||
640 | } | ||||
641 | |||||
642 | /// When set to true, any unmapped warnings are ignored. | ||||
643 | /// | ||||
644 | /// If this and WarningsAsErrors are both set, then this one wins. | ||||
645 | void setIgnoreAllWarnings(bool Val) { | ||||
646 | GetCurDiagState()->IgnoreAllWarnings = Val; | ||||
647 | } | ||||
648 | bool getIgnoreAllWarnings() const { | ||||
649 | return GetCurDiagState()->IgnoreAllWarnings; | ||||
650 | } | ||||
651 | |||||
652 | /// When set to true, any unmapped ignored warnings are no longer | ||||
653 | /// ignored. | ||||
654 | /// | ||||
655 | /// If this and IgnoreAllWarnings are both set, then that one wins. | ||||
656 | void setEnableAllWarnings(bool Val) { | ||||
657 | GetCurDiagState()->EnableAllWarnings = Val; | ||||
658 | } | ||||
659 | bool getEnableAllWarnings() const { | ||||
660 | return GetCurDiagState()->EnableAllWarnings; | ||||
661 | } | ||||
662 | |||||
663 | /// When set to true, any warnings reported are issued as errors. | ||||
664 | void setWarningsAsErrors(bool Val) { | ||||
665 | GetCurDiagState()->WarningsAsErrors = Val; | ||||
666 | } | ||||
667 | bool getWarningsAsErrors() const { | ||||
668 | return GetCurDiagState()->WarningsAsErrors; | ||||
669 | } | ||||
670 | |||||
671 | /// When set to true, any error reported is made a fatal error. | ||||
672 | void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; } | ||||
673 | bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; } | ||||
674 | |||||
675 | /// \brief When set to true, any fatal error reported is made an error. | ||||
676 | /// | ||||
677 | /// This setting takes precedence over the setErrorsAsFatal setting above. | ||||
678 | void setFatalsAsError(bool Val) { FatalsAsError = Val; } | ||||
679 | bool getFatalsAsError() const { return FatalsAsError; } | ||||
680 | |||||
681 | /// When set to true mask warnings that come from system headers. | ||||
682 | void setSuppressSystemWarnings(bool Val) { | ||||
683 | GetCurDiagState()->SuppressSystemWarnings = Val; | ||||
684 | } | ||||
685 | bool getSuppressSystemWarnings() const { | ||||
686 | return GetCurDiagState()->SuppressSystemWarnings; | ||||
687 | } | ||||
688 | |||||
689 | /// Suppress all diagnostics, to silence the front end when we | ||||
690 | /// know that we don't want any more diagnostics to be passed along to the | ||||
691 | /// client | ||||
692 | void setSuppressAllDiagnostics(bool Val) { SuppressAllDiagnostics = Val; } | ||||
693 | bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } | ||||
694 | |||||
695 | /// Set type eliding, to skip outputting same types occurring in | ||||
696 | /// template types. | ||||
697 | void setElideType(bool Val) { ElideType = Val; } | ||||
698 | bool getElideType() { return ElideType; } | ||||
699 | |||||
700 | /// Set tree printing, to outputting the template difference in a | ||||
701 | /// tree format. | ||||
702 | void setPrintTemplateTree(bool Val) { PrintTemplateTree = Val; } | ||||
703 | bool getPrintTemplateTree() { return PrintTemplateTree; } | ||||
704 | |||||
705 | /// Set color printing, so the type diffing will inject color markers | ||||
706 | /// into the output. | ||||
707 | void setShowColors(bool Val) { ShowColors = Val; } | ||||
708 | bool getShowColors() { return ShowColors; } | ||||
709 | |||||
710 | /// Specify which overload candidates to show when overload resolution | ||||
711 | /// fails. | ||||
712 | /// | ||||
713 | /// By default, we show all candidates. | ||||
714 | void setShowOverloads(OverloadsShown Val) { | ||||
715 | ShowOverloads = Val; | ||||
716 | } | ||||
717 | OverloadsShown getShowOverloads() const { return ShowOverloads; } | ||||
718 | |||||
719 | /// When a call or operator fails, print out up to this many candidate | ||||
720 | /// overloads as suggestions. | ||||
721 | /// | ||||
722 | /// With Ovl_Best, we set a high limit for the first nontrivial overload set | ||||
723 | /// we print, and a lower limit for later sets. This way the user has a | ||||
724 | /// chance of diagnosing at least one callsite in their program without | ||||
725 | /// having to recompile with -fshow-overloads=all. | ||||
726 | unsigned getNumOverloadCandidatesToShow() const { | ||||
727 | switch (getShowOverloads()) { | ||||
728 | case Ovl_All: | ||||
729 | // INT_MAX rather than UINT_MAX so that we don't have to think about the | ||||
730 | // effect of implicit conversions on this value. In practice we'll never | ||||
731 | // hit 2^31 candidates anyway. | ||||
732 | return std::numeric_limits<int>::max(); | ||||
733 | case Ovl_Best: | ||||
734 | return NumOverloadsToShow; | ||||
735 | } | ||||
736 | llvm_unreachable("invalid OverloadsShown kind")::llvm::llvm_unreachable_internal("invalid OverloadsShown kind" , "clang/include/clang/Basic/Diagnostic.h", 736); | ||||
737 | } | ||||
738 | |||||
739 | /// Call this after showing N overload candidates. This influences the value | ||||
740 | /// returned by later calls to getNumOverloadCandidatesToShow(). | ||||
741 | void overloadCandidatesShown(unsigned N) { | ||||
742 | // Current heuristic: Start out with a large value for NumOverloadsToShow, | ||||
743 | // and then once we print one nontrivially-large overload set, decrease it | ||||
744 | // for future calls. | ||||
745 | if (N > 4) { | ||||
746 | NumOverloadsToShow = 4; | ||||
747 | } | ||||
748 | } | ||||
749 | |||||
750 | /// Pretend that the last diagnostic issued was ignored, so any | ||||
751 | /// subsequent notes will be suppressed, or restore a prior ignoring | ||||
752 | /// state after ignoring some diagnostics and their notes, possibly in | ||||
753 | /// the middle of another diagnostic. | ||||
754 | /// | ||||
755 | /// This can be used by clients who suppress diagnostics themselves. | ||||
756 | void setLastDiagnosticIgnored(bool Ignored) { | ||||
757 | if (LastDiagLevel == DiagnosticIDs::Fatal) | ||||
758 | FatalErrorOccurred = true; | ||||
759 | LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning; | ||||
760 | } | ||||
761 | |||||
762 | /// Determine whether the previous diagnostic was ignored. This can | ||||
763 | /// be used by clients that want to determine whether notes attached to a | ||||
764 | /// diagnostic will be suppressed. | ||||
765 | bool isLastDiagnosticIgnored() const { | ||||
766 | return LastDiagLevel == DiagnosticIDs::Ignored; | ||||
767 | } | ||||
768 | |||||
769 | /// Controls whether otherwise-unmapped extension diagnostics are | ||||
770 | /// mapped onto ignore/warning/error. | ||||
771 | /// | ||||
772 | /// This corresponds to the GCC -pedantic and -pedantic-errors option. | ||||
773 | void setExtensionHandlingBehavior(diag::Severity H) { | ||||
774 | GetCurDiagState()->ExtBehavior = H; | ||||
775 | } | ||||
776 | diag::Severity getExtensionHandlingBehavior() const { | ||||
777 | return GetCurDiagState()->ExtBehavior; | ||||
778 | } | ||||
779 | |||||
780 | /// Counter bumped when an __extension__ block is/ encountered. | ||||
781 | /// | ||||
782 | /// When non-zero, all extension diagnostics are entirely silenced, no | ||||
783 | /// matter how they are mapped. | ||||
784 | void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } | ||||
785 | void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } | ||||
786 | bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } | ||||
787 | |||||
788 | /// This allows the client to specify that certain warnings are | ||||
789 | /// ignored. | ||||
790 | /// | ||||
791 | /// Notes can never be mapped, errors can only be mapped to fatal, and | ||||
792 | /// WARNINGs and EXTENSIONs can be mapped arbitrarily. | ||||
793 | /// | ||||
794 | /// \param Loc The source location that this change of diagnostic state should | ||||
795 | /// take affect. It can be null if we are setting the latest state. | ||||
796 | void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc); | ||||
797 | |||||
798 | /// Change an entire diagnostic group (e.g. "unknown-pragmas") to | ||||
799 | /// have the specified mapping. | ||||
800 | /// | ||||
801 | /// \returns true (and ignores the request) if "Group" was unknown, false | ||||
802 | /// otherwise. | ||||
803 | /// | ||||
804 | /// \param Flavor The flavor of group to affect. -Rfoo does not affect the | ||||
805 | /// state of the -Wfoo group and vice versa. | ||||
806 | /// | ||||
807 | /// \param Loc The source location that this change of diagnostic state should | ||||
808 | /// take affect. It can be null if we are setting the state from command-line. | ||||
809 | bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, | ||||
810 | diag::Severity Map, | ||||
811 | SourceLocation Loc = SourceLocation()); | ||||
812 | bool setSeverityForGroup(diag::Flavor Flavor, diag::Group Group, | ||||
813 | diag::Severity Map, | ||||
814 | SourceLocation Loc = SourceLocation()); | ||||
815 | |||||
816 | /// Set the warning-as-error flag for the given diagnostic group. | ||||
817 | /// | ||||
818 | /// This function always only operates on the current diagnostic state. | ||||
819 | /// | ||||
820 | /// \returns True if the given group is unknown, false otherwise. | ||||
821 | bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled); | ||||
822 | |||||
823 | /// Set the error-as-fatal flag for the given diagnostic group. | ||||
824 | /// | ||||
825 | /// This function always only operates on the current diagnostic state. | ||||
826 | /// | ||||
827 | /// \returns True if the given group is unknown, false otherwise. | ||||
828 | bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled); | ||||
829 | |||||
830 | /// Add the specified mapping to all diagnostics of the specified | ||||
831 | /// flavor. | ||||
832 | /// | ||||
833 | /// Mainly to be used by -Wno-everything to disable all warnings but allow | ||||
834 | /// subsequent -W options to enable specific warnings. | ||||
835 | void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, | ||||
836 | SourceLocation Loc = SourceLocation()); | ||||
837 | |||||
838 | bool hasErrorOccurred() const { return ErrorOccurred; } | ||||
839 | |||||
840 | /// Errors that actually prevent compilation, not those that are | ||||
841 | /// upgraded from a warning by -Werror. | ||||
842 | bool hasUncompilableErrorOccurred() const { | ||||
843 | return UncompilableErrorOccurred; | ||||
844 | } | ||||
845 | bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } | ||||
846 | |||||
847 | /// Determine whether any kind of unrecoverable error has occurred. | ||||
848 | bool hasUnrecoverableErrorOccurred() const { | ||||
849 | return FatalErrorOccurred || UnrecoverableErrorOccurred; | ||||
850 | } | ||||
851 | |||||
852 | unsigned getNumErrors() const { return NumErrors; } | ||||
853 | unsigned getNumWarnings() const { return NumWarnings; } | ||||
854 | |||||
855 | void setNumWarnings(unsigned NumWarnings) { | ||||
856 | this->NumWarnings = NumWarnings; | ||||
857 | } | ||||
858 | |||||
859 | /// Return an ID for a diagnostic with the specified format string and | ||||
860 | /// level. | ||||
861 | /// | ||||
862 | /// If this is the first request for this diagnostic, it is registered and | ||||
863 | /// created, otherwise the existing ID is returned. | ||||
864 | /// | ||||
865 | /// \param FormatString A fixed diagnostic format string that will be hashed | ||||
866 | /// and mapped to a unique DiagID. | ||||
867 | template <unsigned N> | ||||
868 | unsigned getCustomDiagID(Level L, const char (&FormatString)[N]) { | ||||
869 | return Diags->getCustomDiagID((DiagnosticIDs::Level)L, | ||||
870 | StringRef(FormatString, N - 1)); | ||||
871 | } | ||||
872 | |||||
873 | /// Converts a diagnostic argument (as an intptr_t) into the string | ||||
874 | /// that represents it. | ||||
875 | void ConvertArgToString(ArgumentKind Kind, intptr_t Val, | ||||
876 | StringRef Modifier, StringRef Argument, | ||||
877 | ArrayRef<ArgumentValue> PrevArgs, | ||||
878 | SmallVectorImpl<char> &Output, | ||||
879 | ArrayRef<intptr_t> QualTypeVals) const { | ||||
880 | ArgToStringFn(Kind, Val, Modifier, Argument, PrevArgs, Output, | ||||
881 | ArgToStringCookie, QualTypeVals); | ||||
882 | } | ||||
883 | |||||
884 | void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { | ||||
885 | ArgToStringFn = Fn; | ||||
886 | ArgToStringCookie = Cookie; | ||||
887 | } | ||||
888 | |||||
889 | /// Note that the prior diagnostic was emitted by some other | ||||
890 | /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic. | ||||
891 | void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) { | ||||
892 | LastDiagLevel = Other.LastDiagLevel; | ||||
893 | } | ||||
894 | |||||
895 | /// Reset the state of the diagnostic object to its initial configuration. | ||||
896 | /// \param[in] soft - if true, doesn't reset the diagnostic mappings and state | ||||
897 | void Reset(bool soft = false); | ||||
898 | |||||
899 | //===--------------------------------------------------------------------===// | ||||
900 | // DiagnosticsEngine classification and reporting interfaces. | ||||
901 | // | ||||
902 | |||||
903 | /// Determine whether the diagnostic is known to be ignored. | ||||
904 | /// | ||||
905 | /// This can be used to opportunistically avoid expensive checks when it's | ||||
906 | /// known for certain that the diagnostic has been suppressed at the | ||||
907 | /// specified location \p Loc. | ||||
908 | /// | ||||
909 | /// \param Loc The source location we are interested in finding out the | ||||
910 | /// diagnostic state. Can be null in order to query the latest state. | ||||
911 | bool isIgnored(unsigned DiagID, SourceLocation Loc) const { | ||||
912 | return Diags->getDiagnosticSeverity(DiagID, Loc, *this) == | ||||
913 | diag::Severity::Ignored; | ||||
914 | } | ||||
915 | |||||
916 | /// Based on the way the client configured the DiagnosticsEngine | ||||
917 | /// object, classify the specified diagnostic ID into a Level, consumable by | ||||
918 | /// the DiagnosticConsumer. | ||||
919 | /// | ||||
920 | /// To preserve invariant assumptions, this function should not be used to | ||||
921 | /// influence parse or semantic analysis actions. Instead consider using | ||||
922 | /// \c isIgnored(). | ||||
923 | /// | ||||
924 | /// \param Loc The source location we are interested in finding out the | ||||
925 | /// diagnostic state. Can be null in order to query the latest state. | ||||
926 | Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { | ||||
927 | return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this); | ||||
928 | } | ||||
929 | |||||
930 | /// Issue the message to the client. | ||||
931 | /// | ||||
932 | /// This actually returns an instance of DiagnosticBuilder which emits the | ||||
933 | /// diagnostics (through @c ProcessDiag) when it is destroyed. | ||||
934 | /// | ||||
935 | /// \param DiagID A member of the @c diag::kind enum. | ||||
936 | /// \param Loc Represents the source location associated with the diagnostic, | ||||
937 | /// which can be an invalid location if no position information is available. | ||||
938 | inline DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID); | ||||
939 | inline DiagnosticBuilder Report(unsigned DiagID); | ||||
940 | |||||
941 | void Report(const StoredDiagnostic &storedDiag); | ||||
942 | |||||
943 | /// Determine whethere there is already a diagnostic in flight. | ||||
944 | bool isDiagnosticInFlight() const { | ||||
945 | return CurDiagID != std::numeric_limits<unsigned>::max(); | ||||
946 | } | ||||
947 | |||||
948 | /// Set the "delayed" diagnostic that will be emitted once | ||||
949 | /// the current diagnostic completes. | ||||
950 | /// | ||||
951 | /// If a diagnostic is already in-flight but the front end must | ||||
952 | /// report a problem (e.g., with an inconsistent file system | ||||
953 | /// state), this routine sets a "delayed" diagnostic that will be | ||||
954 | /// emitted after the current diagnostic completes. This should | ||||
955 | /// only be used for fatal errors detected at inconvenient | ||||
956 | /// times. If emitting a delayed diagnostic causes a second delayed | ||||
957 | /// diagnostic to be introduced, that second delayed diagnostic | ||||
958 | /// will be ignored. | ||||
959 | /// | ||||
960 | /// \param DiagID The ID of the diagnostic being delayed. | ||||
961 | /// | ||||
962 | /// \param Arg1 A string argument that will be provided to the | ||||
963 | /// diagnostic. A copy of this string will be stored in the | ||||
964 | /// DiagnosticsEngine object itself. | ||||
965 | /// | ||||
966 | /// \param Arg2 A string argument that will be provided to the | ||||
967 | /// diagnostic. A copy of this string will be stored in the | ||||
968 | /// DiagnosticsEngine object itself. | ||||
969 | /// | ||||
970 | /// \param Arg3 A string argument that will be provided to the | ||||
971 | /// diagnostic. A copy of this string will be stored in the | ||||
972 | /// DiagnosticsEngine object itself. | ||||
973 | void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "", | ||||
974 | StringRef Arg2 = "", StringRef Arg3 = ""); | ||||
975 | |||||
976 | /// Clear out the current diagnostic. | ||||
977 | void Clear() { CurDiagID = std::numeric_limits<unsigned>::max(); } | ||||
978 | |||||
979 | /// Return the value associated with this diagnostic flag. | ||||
980 | StringRef getFlagValue() const { return FlagValue; } | ||||
981 | |||||
982 | private: | ||||
983 | // This is private state used by DiagnosticBuilder. We put it here instead of | ||||
984 | // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight | ||||
985 | // object. This implementation choice means that we can only have one | ||||
986 | // diagnostic "in flight" at a time, but this seems to be a reasonable | ||||
987 | // tradeoff to keep these objects small. Assertions verify that only one | ||||
988 | // diagnostic is in flight at a time. | ||||
989 | friend class Diagnostic; | ||||
990 | friend class DiagnosticBuilder; | ||||
991 | friend class DiagnosticErrorTrap; | ||||
992 | friend class DiagnosticIDs; | ||||
993 | friend class PartialDiagnostic; | ||||
994 | |||||
995 | /// Report the delayed diagnostic. | ||||
996 | void ReportDelayed(); | ||||
997 | |||||
998 | /// The location of the current diagnostic that is in flight. | ||||
999 | SourceLocation CurDiagLoc; | ||||
1000 | |||||
1001 | /// The ID of the current diagnostic that is in flight. | ||||
1002 | /// | ||||
1003 | /// This is set to std::numeric_limits<unsigned>::max() when there is no | ||||
1004 | /// diagnostic in flight. | ||||
1005 | unsigned CurDiagID; | ||||
1006 | |||||
1007 | enum { | ||||
1008 | /// The maximum number of arguments we can hold. | ||||
1009 | /// | ||||
1010 | /// We currently only support up to 10 arguments (%0-%9). A single | ||||
1011 | /// diagnostic with more than that almost certainly has to be simplified | ||||
1012 | /// anyway. | ||||
1013 | MaxArguments = DiagnosticStorage::MaxArguments, | ||||
1014 | }; | ||||
1015 | |||||
1016 | DiagnosticStorage DiagStorage; | ||||
1017 | |||||
1018 | DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) { | ||||
1019 | bool isPragma = L.isValid(); | ||||
1020 | DiagnosticMapping Mapping = | ||||
1021 | DiagnosticMapping::Make(Map, /*IsUser=*/true, isPragma); | ||||
1022 | |||||
1023 | // If this is a pragma mapping, then set the diagnostic mapping flags so | ||||
1024 | // that we override command line options. | ||||
1025 | if (isPragma) { | ||||
1026 | Mapping.setNoWarningAsError(true); | ||||
1027 | Mapping.setNoErrorAsFatal(true); | ||||
1028 | } | ||||
1029 | |||||
1030 | return Mapping; | ||||
1031 | } | ||||
1032 | |||||
1033 | /// Used to report a diagnostic that is finally fully formed. | ||||
1034 | /// | ||||
1035 | /// \returns true if the diagnostic was emitted, false if it was suppressed. | ||||
1036 | bool ProcessDiag() { | ||||
1037 | return Diags->ProcessDiag(*this); | ||||
1038 | } | ||||
1039 | |||||
1040 | /// @name Diagnostic Emission | ||||
1041 | /// @{ | ||||
1042 | protected: | ||||
1043 | friend class ASTReader; | ||||
1044 | friend class ASTWriter; | ||||
1045 | |||||
1046 | // Sema requires access to the following functions because the current design | ||||
1047 | // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to | ||||
1048 | // access us directly to ensure we minimize the emitted code for the common | ||||
1049 | // Sema::Diag() patterns. | ||||
1050 | friend class Sema; | ||||
1051 | |||||
1052 | /// Emit the current diagnostic and clear the diagnostic state. | ||||
1053 | /// | ||||
1054 | /// \param Force Emit the diagnostic regardless of suppression settings. | ||||
1055 | bool EmitCurrentDiagnostic(bool Force = false); | ||||
1056 | |||||
1057 | unsigned getCurrentDiagID() const { return CurDiagID; } | ||||
1058 | |||||
1059 | SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; } | ||||
1060 | |||||
1061 | /// @} | ||||
1062 | }; | ||||
1063 | |||||
1064 | /// RAII class that determines when any errors have occurred | ||||
1065 | /// between the time the instance was created and the time it was | ||||
1066 | /// queried. | ||||
1067 | /// | ||||
1068 | /// Note that you almost certainly do not want to use this. It's usually | ||||
1069 | /// meaningless to ask whether a particular scope triggered an error message, | ||||
1070 | /// because error messages outside that scope can mark things invalid (or cause | ||||
1071 | /// us to reach an error limit), which can suppress errors within that scope. | ||||
1072 | class DiagnosticErrorTrap { | ||||
1073 | DiagnosticsEngine &Diag; | ||||
1074 | unsigned NumErrors; | ||||
1075 | unsigned NumUnrecoverableErrors; | ||||
1076 | |||||
1077 | public: | ||||
1078 | explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag) | ||||
1079 | : Diag(Diag) { reset(); } | ||||
1080 | |||||
1081 | /// Determine whether any errors have occurred since this | ||||
1082 | /// object instance was created. | ||||
1083 | bool hasErrorOccurred() const { | ||||
1084 | return Diag.TrapNumErrorsOccurred > NumErrors; | ||||
1085 | } | ||||
1086 | |||||
1087 | /// Determine whether any unrecoverable errors have occurred since this | ||||
1088 | /// object instance was created. | ||||
1089 | bool hasUnrecoverableErrorOccurred() const { | ||||
1090 | return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors; | ||||
1091 | } | ||||
1092 | |||||
1093 | /// Set to initial state of "no errors occurred". | ||||
1094 | void reset() { | ||||
1095 | NumErrors = Diag.TrapNumErrorsOccurred; | ||||
1096 | NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred; | ||||
1097 | } | ||||
1098 | }; | ||||
1099 | |||||
1100 | /// The streaming interface shared between DiagnosticBuilder and | ||||
1101 | /// PartialDiagnostic. This class is not intended to be constructed directly | ||||
1102 | /// but only as base class of DiagnosticBuilder and PartialDiagnostic builder. | ||||
1103 | /// | ||||
1104 | /// Any new type of argument accepted by DiagnosticBuilder and PartialDiagnostic | ||||
1105 | /// should be implemented as a '<<' operator of StreamingDiagnostic, e.g. | ||||
1106 | /// | ||||
1107 | /// const StreamingDiagnostic& | ||||
1108 | /// operator<<(const StreamingDiagnostic&, NewArgType); | ||||
1109 | /// | ||||
1110 | class StreamingDiagnostic { | ||||
1111 | public: | ||||
1112 | /// An allocator for DiagnosticStorage objects, which uses a small cache to | ||||
1113 | /// objects, used to reduce malloc()/free() traffic for partial diagnostics. | ||||
1114 | class DiagStorageAllocator { | ||||
1115 | static const unsigned NumCached = 16; | ||||
1116 | DiagnosticStorage Cached[NumCached]; | ||||
1117 | DiagnosticStorage *FreeList[NumCached]; | ||||
1118 | unsigned NumFreeListEntries; | ||||
1119 | |||||
1120 | public: | ||||
1121 | DiagStorageAllocator(); | ||||
1122 | ~DiagStorageAllocator(); | ||||
1123 | |||||
1124 | /// Allocate new storage. | ||||
1125 | DiagnosticStorage *Allocate() { | ||||
1126 | if (NumFreeListEntries == 0) | ||||
1127 | return new DiagnosticStorage; | ||||
1128 | |||||
1129 | DiagnosticStorage *Result = FreeList[--NumFreeListEntries]; | ||||
1130 | Result->NumDiagArgs = 0; | ||||
1131 | Result->DiagRanges.clear(); | ||||
1132 | Result->FixItHints.clear(); | ||||
1133 | return Result; | ||||
1134 | } | ||||
1135 | |||||
1136 | /// Free the given storage object. | ||||
1137 | void Deallocate(DiagnosticStorage *S) { | ||||
1138 | if (S >= Cached && S <= Cached + NumCached) { | ||||
1139 | FreeList[NumFreeListEntries++] = S; | ||||
1140 | return; | ||||
1141 | } | ||||
1142 | |||||
1143 | delete S; | ||||
1144 | } | ||||
1145 | }; | ||||
1146 | |||||
1147 | protected: | ||||
1148 | mutable DiagnosticStorage *DiagStorage = nullptr; | ||||
1149 | |||||
1150 | /// Allocator used to allocate storage for this diagnostic. | ||||
1151 | DiagStorageAllocator *Allocator = nullptr; | ||||
1152 | |||||
1153 | public: | ||||
1154 | /// Retrieve storage for this particular diagnostic. | ||||
1155 | DiagnosticStorage *getStorage() const { | ||||
1156 | if (DiagStorage) | ||||
1157 | return DiagStorage; | ||||
1158 | |||||
1159 | assert(Allocator)(static_cast <bool> (Allocator) ? void (0) : __assert_fail ("Allocator", "clang/include/clang/Basic/Diagnostic.h", 1159 , __extension__ __PRETTY_FUNCTION__)); | ||||
1160 | DiagStorage = Allocator->Allocate(); | ||||
1161 | return DiagStorage; | ||||
1162 | } | ||||
1163 | |||||
1164 | void freeStorage() { | ||||
1165 | if (!DiagStorage) | ||||
1166 | return; | ||||
1167 | |||||
1168 | // The hot path for PartialDiagnostic is when we just used it to wrap an ID | ||||
1169 | // (typically so we have the flexibility of passing a more complex | ||||
1170 | // diagnostic into the callee, but that does not commonly occur). | ||||
1171 | // | ||||
1172 | // Split this out into a slow function for silly compilers (*cough*) which | ||||
1173 | // can't do decent partial inlining. | ||||
1174 | freeStorageSlow(); | ||||
1175 | } | ||||
1176 | |||||
1177 | void freeStorageSlow() { | ||||
1178 | if (!Allocator) | ||||
1179 | return; | ||||
1180 | Allocator->Deallocate(DiagStorage); | ||||
1181 | DiagStorage = nullptr; | ||||
1182 | } | ||||
1183 | |||||
1184 | void AddTaggedVal(uint64_t V, DiagnosticsEngine::ArgumentKind Kind) const { | ||||
1185 | if (!DiagStorage
| ||||
1186 | DiagStorage = getStorage(); | ||||
1187 | |||||
1188 | assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage ::MaxArguments && "Too many arguments to diagnostic!" ) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1189, __extension__ __PRETTY_FUNCTION__)) | ||||
| |||||
1189 | "Too many arguments to diagnostic!")(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage ::MaxArguments && "Too many arguments to diagnostic!" ) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1189, __extension__ __PRETTY_FUNCTION__)); | ||||
1190 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; | ||||
1191 | DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; | ||||
1192 | } | ||||
1193 | |||||
1194 | void AddString(StringRef V) const { | ||||
1195 | if (!DiagStorage) | ||||
1196 | DiagStorage = getStorage(); | ||||
1197 | |||||
1198 | assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage ::MaxArguments && "Too many arguments to diagnostic!" ) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1199, __extension__ __PRETTY_FUNCTION__)) | ||||
1199 | "Too many arguments to diagnostic!")(static_cast <bool> (DiagStorage->NumDiagArgs < DiagnosticStorage ::MaxArguments && "Too many arguments to diagnostic!" ) ? void (0) : __assert_fail ("DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments && \"Too many arguments to diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1199, __extension__ __PRETTY_FUNCTION__)); | ||||
1200 | DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = | ||||
1201 | DiagnosticsEngine::ak_std_string; | ||||
1202 | DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = std::string(V); | ||||
1203 | } | ||||
1204 | |||||
1205 | void AddSourceRange(const CharSourceRange &R) const { | ||||
1206 | if (!DiagStorage) | ||||
1207 | DiagStorage = getStorage(); | ||||
1208 | |||||
1209 | DiagStorage->DiagRanges.push_back(R); | ||||
1210 | } | ||||
1211 | |||||
1212 | void AddFixItHint(const FixItHint &Hint) const { | ||||
1213 | if (Hint.isNull()) | ||||
1214 | return; | ||||
1215 | |||||
1216 | if (!DiagStorage) | ||||
1217 | DiagStorage = getStorage(); | ||||
1218 | |||||
1219 | DiagStorage->FixItHints.push_back(Hint); | ||||
1220 | } | ||||
1221 | |||||
1222 | /// Conversion of StreamingDiagnostic to bool always returns \c true. | ||||
1223 | /// | ||||
1224 | /// This allows is to be used in boolean error contexts (where \c true is | ||||
1225 | /// used to indicate that an error has occurred), like: | ||||
1226 | /// \code | ||||
1227 | /// return Diag(...); | ||||
1228 | /// \endcode | ||||
1229 | operator bool() const { return true; } | ||||
1230 | |||||
1231 | protected: | ||||
1232 | StreamingDiagnostic() = default; | ||||
1233 | |||||
1234 | /// Construct with an external storage not owned by itself. The allocator | ||||
1235 | /// is a null pointer in this case. | ||||
1236 | explicit StreamingDiagnostic(DiagnosticStorage *Storage) | ||||
1237 | : DiagStorage(Storage) {} | ||||
1238 | |||||
1239 | /// Construct with a storage allocator which will manage the storage. The | ||||
1240 | /// allocator is not a null pointer in this case. | ||||
1241 | explicit StreamingDiagnostic(DiagStorageAllocator &Alloc) | ||||
1242 | : Allocator(&Alloc) {} | ||||
1243 | |||||
1244 | StreamingDiagnostic(const StreamingDiagnostic &Diag) = default; | ||||
1245 | StreamingDiagnostic(StreamingDiagnostic &&Diag) = default; | ||||
1246 | |||||
1247 | ~StreamingDiagnostic() { freeStorage(); } | ||||
1248 | }; | ||||
1249 | |||||
1250 | //===----------------------------------------------------------------------===// | ||||
1251 | // DiagnosticBuilder | ||||
1252 | //===----------------------------------------------------------------------===// | ||||
1253 | |||||
1254 | /// A little helper class used to produce diagnostics. | ||||
1255 | /// | ||||
1256 | /// This is constructed by the DiagnosticsEngine::Report method, and | ||||
1257 | /// allows insertion of extra information (arguments and source ranges) into | ||||
1258 | /// the currently "in flight" diagnostic. When the temporary for the builder | ||||
1259 | /// is destroyed, the diagnostic is issued. | ||||
1260 | /// | ||||
1261 | /// Note that many of these will be created as temporary objects (many call | ||||
1262 | /// sites), so we want them to be small and we never want their address taken. | ||||
1263 | /// This ensures that compilers with somewhat reasonable optimizers will promote | ||||
1264 | /// the common fields to registers, eliminating increments of the NumArgs field, | ||||
1265 | /// for example. | ||||
1266 | class DiagnosticBuilder : public StreamingDiagnostic { | ||||
1267 | friend class DiagnosticsEngine; | ||||
1268 | friend class PartialDiagnostic; | ||||
1269 | |||||
1270 | mutable DiagnosticsEngine *DiagObj = nullptr; | ||||
1271 | |||||
1272 | /// Status variable indicating if this diagnostic is still active. | ||||
1273 | /// | ||||
1274 | // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)), | ||||
1275 | // but LLVM is not currently smart enough to eliminate the null check that | ||||
1276 | // Emit() would end up with if we used that as our status variable. | ||||
1277 | mutable bool IsActive = false; | ||||
1278 | |||||
1279 | /// Flag indicating that this diagnostic is being emitted via a | ||||
1280 | /// call to ForceEmit. | ||||
1281 | mutable bool IsForceEmit = false; | ||||
1282 | |||||
1283 | DiagnosticBuilder() = default; | ||||
1284 | |||||
1285 | explicit DiagnosticBuilder(DiagnosticsEngine *diagObj) | ||||
1286 | : StreamingDiagnostic(&diagObj->DiagStorage), DiagObj(diagObj), | ||||
1287 | IsActive(true) { | ||||
1288 | assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!")(static_cast <bool> (diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!" ) ? void (0) : __assert_fail ("diagObj && \"DiagnosticBuilder requires a valid DiagnosticsEngine!\"" , "clang/include/clang/Basic/Diagnostic.h", 1288, __extension__ __PRETTY_FUNCTION__)); | ||||
1289 | assert(DiagStorage &&(static_cast <bool> (DiagStorage && "DiagnosticBuilder requires a valid DiagnosticStorage!" ) ? void (0) : __assert_fail ("DiagStorage && \"DiagnosticBuilder requires a valid DiagnosticStorage!\"" , "clang/include/clang/Basic/Diagnostic.h", 1290, __extension__ __PRETTY_FUNCTION__)) | ||||
1290 | "DiagnosticBuilder requires a valid DiagnosticStorage!")(static_cast <bool> (DiagStorage && "DiagnosticBuilder requires a valid DiagnosticStorage!" ) ? void (0) : __assert_fail ("DiagStorage && \"DiagnosticBuilder requires a valid DiagnosticStorage!\"" , "clang/include/clang/Basic/Diagnostic.h", 1290, __extension__ __PRETTY_FUNCTION__)); | ||||
1291 | DiagStorage->NumDiagArgs = 0; | ||||
1292 | DiagStorage->DiagRanges.clear(); | ||||
1293 | DiagStorage->FixItHints.clear(); | ||||
1294 | } | ||||
1295 | |||||
1296 | protected: | ||||
1297 | /// Clear out the current diagnostic. | ||||
1298 | void Clear() const { | ||||
1299 | DiagObj = nullptr; | ||||
1300 | IsActive = false; | ||||
1301 | IsForceEmit = false; | ||||
1302 | } | ||||
1303 | |||||
1304 | /// Determine whether this diagnostic is still active. | ||||
1305 | bool isActive() const { return IsActive; } | ||||
1306 | |||||
1307 | /// Force the diagnostic builder to emit the diagnostic now. | ||||
1308 | /// | ||||
1309 | /// Once this function has been called, the DiagnosticBuilder object | ||||
1310 | /// should not be used again before it is destroyed. | ||||
1311 | /// | ||||
1312 | /// \returns true if a diagnostic was emitted, false if the | ||||
1313 | /// diagnostic was suppressed. | ||||
1314 | bool Emit() { | ||||
1315 | // If this diagnostic is inactive, then its soul was stolen by the copy ctor | ||||
1316 | // (or by a subclass, as in SemaDiagnosticBuilder). | ||||
1317 | if (!isActive()) return false; | ||||
1318 | |||||
1319 | // Process the diagnostic. | ||||
1320 | bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit); | ||||
1321 | |||||
1322 | // This diagnostic is dead. | ||||
1323 | Clear(); | ||||
1324 | |||||
1325 | return Result; | ||||
1326 | } | ||||
1327 | |||||
1328 | public: | ||||
1329 | /// Copy constructor. When copied, this "takes" the diagnostic info from the | ||||
1330 | /// input and neuters it. | ||||
1331 | DiagnosticBuilder(const DiagnosticBuilder &D) : StreamingDiagnostic() { | ||||
1332 | DiagObj = D.DiagObj; | ||||
1333 | DiagStorage = D.DiagStorage; | ||||
1334 | IsActive = D.IsActive; | ||||
1335 | IsForceEmit = D.IsForceEmit; | ||||
1336 | D.Clear(); | ||||
1337 | } | ||||
1338 | |||||
1339 | template <typename T> const DiagnosticBuilder &operator<<(const T &V) const { | ||||
1340 | assert(isActive() && "Clients must not add to cleared diagnostic!")(static_cast <bool> (isActive() && "Clients must not add to cleared diagnostic!" ) ? void (0) : __assert_fail ("isActive() && \"Clients must not add to cleared diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1340, __extension__ __PRETTY_FUNCTION__)); | ||||
1341 | const StreamingDiagnostic &DB = *this; | ||||
1342 | DB << V; | ||||
1343 | return *this; | ||||
1344 | } | ||||
1345 | |||||
1346 | // It is necessary to limit this to rvalue reference to avoid calling this | ||||
1347 | // function with a bitfield lvalue argument since non-const reference to | ||||
1348 | // bitfield is not allowed. | ||||
1349 | template <typename T, | ||||
1350 | typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> | ||||
1351 | const DiagnosticBuilder &operator<<(T &&V) const { | ||||
1352 | assert(isActive() && "Clients must not add to cleared diagnostic!")(static_cast <bool> (isActive() && "Clients must not add to cleared diagnostic!" ) ? void (0) : __assert_fail ("isActive() && \"Clients must not add to cleared diagnostic!\"" , "clang/include/clang/Basic/Diagnostic.h", 1352, __extension__ __PRETTY_FUNCTION__)); | ||||
1353 | const StreamingDiagnostic &DB = *this; | ||||
1354 | DB << std::move(V); | ||||
1355 | return *this; | ||||
1356 | } | ||||
1357 | |||||
1358 | DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete; | ||||
1359 | |||||
1360 | /// Emits the diagnostic. | ||||
1361 | ~DiagnosticBuilder() { Emit(); } | ||||
1362 | |||||
1363 | /// Forces the diagnostic to be emitted. | ||||
1364 | const DiagnosticBuilder &setForceEmit() const { | ||||
1365 | IsForceEmit = true; | ||||
1366 | return *this; | ||||
1367 | } | ||||
1368 | |||||
1369 | void addFlagValue(StringRef V) const { DiagObj->FlagValue = std::string(V); } | ||||
1370 | }; | ||||
1371 | |||||
1372 | struct AddFlagValue { | ||||
1373 | StringRef Val; | ||||
1374 | |||||
1375 | explicit AddFlagValue(StringRef V) : Val(V) {} | ||||
1376 | }; | ||||
1377 | |||||
1378 | /// Register a value for the flag in the current diagnostic. This | ||||
1379 | /// value will be shown as the suffix "=value" after the flag name. It is | ||||
1380 | /// useful in cases where the diagnostic flag accepts values (e.g., | ||||
1381 | /// -Rpass or -Wframe-larger-than). | ||||
1382 | inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, | ||||
1383 | const AddFlagValue V) { | ||||
1384 | DB.addFlagValue(V.Val); | ||||
1385 | return DB; | ||||
1386 | } | ||||
1387 | |||||
1388 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1389 | StringRef S) { | ||||
1390 | DB.AddString(S); | ||||
1391 | return DB; | ||||
1392 | } | ||||
1393 | |||||
1394 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1395 | const char *Str) { | ||||
1396 | DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), | ||||
1397 | DiagnosticsEngine::ak_c_string); | ||||
1398 | return DB; | ||||
1399 | } | ||||
1400 | |||||
1401 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1402 | int I) { | ||||
1403 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); | ||||
1404 | return DB; | ||||
1405 | } | ||||
1406 | |||||
1407 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1408 | long I) { | ||||
1409 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); | ||||
1410 | return DB; | ||||
1411 | } | ||||
1412 | |||||
1413 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1414 | long long I) { | ||||
1415 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); | ||||
1416 | return DB; | ||||
1417 | } | ||||
1418 | |||||
1419 | // We use enable_if here to prevent that this overload is selected for | ||||
1420 | // pointers or other arguments that are implicitly convertible to bool. | ||||
1421 | template <typename T> | ||||
1422 | inline std::enable_if_t<std::is_same<T, bool>::value, | ||||
1423 | const StreamingDiagnostic &> | ||||
1424 | operator<<(const StreamingDiagnostic &DB, T I) { | ||||
1425 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); | ||||
1426 | return DB; | ||||
1427 | } | ||||
1428 | |||||
1429 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1430 | unsigned I) { | ||||
1431 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); | ||||
1432 | return DB; | ||||
1433 | } | ||||
1434 | |||||
1435 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1436 | unsigned long I) { | ||||
1437 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); | ||||
1438 | return DB; | ||||
1439 | } | ||||
1440 | |||||
1441 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1442 | unsigned long long I) { | ||||
1443 | DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); | ||||
1444 | return DB; | ||||
1445 | } | ||||
1446 | |||||
1447 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1448 | tok::TokenKind I) { | ||||
1449 | DB.AddTaggedVal(static_cast<unsigned>(I), DiagnosticsEngine::ak_tokenkind); | ||||
1450 | return DB; | ||||
1451 | } | ||||
1452 | |||||
1453 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1454 | const IdentifierInfo *II) { | ||||
1455 | DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), | ||||
1456 | DiagnosticsEngine::ak_identifierinfo); | ||||
1457 | return DB; | ||||
1458 | } | ||||
1459 | |||||
1460 | // Adds a DeclContext to the diagnostic. The enable_if template magic is here | ||||
1461 | // so that we only match those arguments that are (statically) DeclContexts; | ||||
1462 | // other arguments that derive from DeclContext (e.g., RecordDecls) will not | ||||
1463 | // match. | ||||
1464 | template <typename T> | ||||
1465 | inline std::enable_if_t< | ||||
1466 | std::is_same<std::remove_const_t<T>, DeclContext>::value, | ||||
1467 | const StreamingDiagnostic &> | ||||
1468 | operator<<(const StreamingDiagnostic &DB, T *DC) { | ||||
1469 | DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC), | ||||
1470 | DiagnosticsEngine::ak_declcontext); | ||||
1471 | return DB; | ||||
1472 | } | ||||
1473 | |||||
1474 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1475 | SourceLocation L) { | ||||
1476 | DB.AddSourceRange(CharSourceRange::getTokenRange(L)); | ||||
1477 | return DB; | ||||
1478 | } | ||||
1479 | |||||
1480 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1481 | SourceRange R) { | ||||
1482 | DB.AddSourceRange(CharSourceRange::getTokenRange(R)); | ||||
1483 | return DB; | ||||
1484 | } | ||||
1485 | |||||
1486 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1487 | ArrayRef<SourceRange> Ranges) { | ||||
1488 | for (SourceRange R : Ranges) | ||||
1489 | DB.AddSourceRange(CharSourceRange::getTokenRange(R)); | ||||
1490 | return DB; | ||||
1491 | } | ||||
1492 | |||||
1493 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1494 | const CharSourceRange &R) { | ||||
1495 | DB.AddSourceRange(R); | ||||
1496 | return DB; | ||||
1497 | } | ||||
1498 | |||||
1499 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1500 | const FixItHint &Hint) { | ||||
1501 | DB.AddFixItHint(Hint); | ||||
1502 | return DB; | ||||
1503 | } | ||||
1504 | |||||
1505 | inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1506 | ArrayRef<FixItHint> Hints) { | ||||
1507 | for (const FixItHint &Hint : Hints) | ||||
1508 | DB.AddFixItHint(Hint); | ||||
1509 | return DB; | ||||
1510 | } | ||||
1511 | |||||
1512 | inline const StreamingDiagnostic & | ||||
1513 | operator<<(const StreamingDiagnostic &DB, | ||||
1514 | const std::optional<SourceRange> &Opt) { | ||||
1515 | if (Opt) | ||||
1516 | DB << *Opt; | ||||
1517 | return DB; | ||||
1518 | } | ||||
1519 | |||||
1520 | inline const StreamingDiagnostic & | ||||
1521 | operator<<(const StreamingDiagnostic &DB, | ||||
1522 | const std::optional<CharSourceRange> &Opt) { | ||||
1523 | if (Opt) | ||||
1524 | DB << *Opt; | ||||
1525 | return DB; | ||||
1526 | } | ||||
1527 | |||||
1528 | inline const StreamingDiagnostic & | ||||
1529 | operator<<(const StreamingDiagnostic &DB, const std::optional<FixItHint> &Opt) { | ||||
1530 | if (Opt) | ||||
1531 | DB << *Opt; | ||||
1532 | return DB; | ||||
1533 | } | ||||
1534 | |||||
1535 | /// A nullability kind paired with a bit indicating whether it used a | ||||
1536 | /// context-sensitive keyword. | ||||
1537 | using DiagNullabilityKind = std::pair<NullabilityKind, bool>; | ||||
1538 | |||||
1539 | const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1540 | DiagNullabilityKind nullability); | ||||
1541 | |||||
1542 | inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, | ||||
1543 | unsigned DiagID) { | ||||
1544 | assert(CurDiagID == std::numeric_limits<unsigned>::max() &&(static_cast <bool> (CurDiagID == std::numeric_limits< unsigned>::max() && "Multiple diagnostics in flight at once!" ) ? void (0) : __assert_fail ("CurDiagID == std::numeric_limits<unsigned>::max() && \"Multiple diagnostics in flight at once!\"" , "clang/include/clang/Basic/Diagnostic.h", 1545, __extension__ __PRETTY_FUNCTION__)) | ||||
1545 | "Multiple diagnostics in flight at once!")(static_cast <bool> (CurDiagID == std::numeric_limits< unsigned>::max() && "Multiple diagnostics in flight at once!" ) ? void (0) : __assert_fail ("CurDiagID == std::numeric_limits<unsigned>::max() && \"Multiple diagnostics in flight at once!\"" , "clang/include/clang/Basic/Diagnostic.h", 1545, __extension__ __PRETTY_FUNCTION__)); | ||||
1546 | CurDiagLoc = Loc; | ||||
1547 | CurDiagID = DiagID; | ||||
1548 | FlagValue.clear(); | ||||
1549 | return DiagnosticBuilder(this); | ||||
1550 | } | ||||
1551 | |||||
1552 | const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, | ||||
1553 | llvm::Error &&E); | ||||
1554 | |||||
1555 | inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) { | ||||
1556 | return Report(SourceLocation(), DiagID); | ||||
1557 | } | ||||
1558 | |||||
1559 | //===----------------------------------------------------------------------===// | ||||
1560 | // Diagnostic | ||||
1561 | //===----------------------------------------------------------------------===// | ||||
1562 | |||||
1563 | /// A little helper class (which is basically a smart pointer that forwards | ||||
1564 | /// info from DiagnosticsEngine) that allows clients to enquire about the | ||||
1565 | /// currently in-flight diagnostic. | ||||
1566 | class Diagnostic { | ||||
1567 | const DiagnosticsEngine *DiagObj; | ||||
1568 | std::optional<StringRef> StoredDiagMessage; | ||||
1569 | |||||
1570 | public: | ||||
1571 | explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {} | ||||
1572 | Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage) | ||||
1573 | : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {} | ||||
1574 | |||||
1575 | const DiagnosticsEngine *getDiags() const { return DiagObj; } | ||||
1576 | unsigned getID() const { return DiagObj->CurDiagID; } | ||||
1577 | const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; } | ||||
1578 | bool hasSourceManager() const { return DiagObj->hasSourceManager(); } | ||||
1579 | SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} | ||||
1580 | |||||
1581 | unsigned getNumArgs() const { return DiagObj->DiagStorage.NumDiagArgs; } | ||||
1582 | |||||
1583 | /// Return the kind of the specified index. | ||||
1584 | /// | ||||
1585 | /// Based on the kind of argument, the accessors below can be used to get | ||||
1586 | /// the value. | ||||
1587 | /// | ||||
1588 | /// \pre Idx < getNumArgs() | ||||
1589 | DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const { | ||||
1590 | assert(Idx < getNumArgs() && "Argument index out of range!")(static_cast <bool> (Idx < getNumArgs() && "Argument index out of range!" ) ? void (0) : __assert_fail ("Idx < getNumArgs() && \"Argument index out of range!\"" , "clang/include/clang/Basic/Diagnostic.h", 1590, __extension__ __PRETTY_FUNCTION__)); | ||||
1591 | return (DiagnosticsEngine::ArgumentKind) | ||||
1592 | DiagObj->DiagStorage.DiagArgumentsKind[Idx]; | ||||
1593 | } | ||||
1594 | |||||
1595 | /// Return the provided argument string specified by \p Idx. | ||||
1596 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_std_string | ||||
1597 | const std::string &getArgStdStr(unsigned Idx) const { | ||||
1598 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_std_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1599, __extension__ __PRETTY_FUNCTION__)) | ||||
1599 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_std_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1599, __extension__ __PRETTY_FUNCTION__)); | ||||
1600 | return DiagObj->DiagStorage.DiagArgumentsStr[Idx]; | ||||
1601 | } | ||||
1602 | |||||
1603 | /// Return the specified C string argument. | ||||
1604 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_c_string | ||||
1605 | const char *getArgCStr(unsigned Idx) const { | ||||
1606 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_c_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_c_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1607, __extension__ __PRETTY_FUNCTION__)) | ||||
1607 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_c_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_c_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1607, __extension__ __PRETTY_FUNCTION__)); | ||||
1608 | return reinterpret_cast<const char *>( | ||||
1609 | DiagObj->DiagStorage.DiagArgumentsVal[Idx]); | ||||
1610 | } | ||||
1611 | |||||
1612 | /// Return the specified signed integer argument. | ||||
1613 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint | ||||
1614 | int64_t getArgSInt(unsigned Idx) const { | ||||
1615 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_sint && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_sint && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1616, __extension__ __PRETTY_FUNCTION__)) | ||||
1616 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_sint && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_sint && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1616, __extension__ __PRETTY_FUNCTION__)); | ||||
1617 | return (int64_t)DiagObj->DiagStorage.DiagArgumentsVal[Idx]; | ||||
1618 | } | ||||
1619 | |||||
1620 | /// Return the specified unsigned integer argument. | ||||
1621 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint | ||||
1622 | uint64_t getArgUInt(unsigned Idx) const { | ||||
1623 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_uint && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_uint && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1624, __extension__ __PRETTY_FUNCTION__)) | ||||
1624 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_uint && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_uint && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1624, __extension__ __PRETTY_FUNCTION__)); | ||||
1625 | return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; | ||||
1626 | } | ||||
1627 | |||||
1628 | /// Return the specified IdentifierInfo argument. | ||||
1629 | /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo | ||||
1630 | const IdentifierInfo *getArgIdentifier(unsigned Idx) const { | ||||
1631 | assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_identifierinfo && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1632, __extension__ __PRETTY_FUNCTION__)) | ||||
1632 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) == DiagnosticsEngine ::ak_identifierinfo && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1632, __extension__ __PRETTY_FUNCTION__)); | ||||
1633 | return reinterpret_cast<IdentifierInfo *>( | ||||
1634 | DiagObj->DiagStorage.DiagArgumentsVal[Idx]); | ||||
1635 | } | ||||
1636 | |||||
1637 | /// Return the specified non-string argument in an opaque form. | ||||
1638 | /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string | ||||
1639 | uint64_t getRawArg(unsigned Idx) const { | ||||
1640 | assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&(static_cast <bool> (getArgKind(Idx) != DiagnosticsEngine ::ak_std_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) != DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1641, __extension__ __PRETTY_FUNCTION__)) | ||||
1641 | "invalid argument accessor!")(static_cast <bool> (getArgKind(Idx) != DiagnosticsEngine ::ak_std_string && "invalid argument accessor!") ? void (0) : __assert_fail ("getArgKind(Idx) != DiagnosticsEngine::ak_std_string && \"invalid argument accessor!\"" , "clang/include/clang/Basic/Diagnostic.h", 1641, __extension__ __PRETTY_FUNCTION__)); | ||||
1642 | return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; | ||||
1643 | } | ||||
1644 | |||||
1645 | /// Return the number of source ranges associated with this diagnostic. | ||||
1646 | unsigned getNumRanges() const { | ||||
1647 | return DiagObj->DiagStorage.DiagRanges.size(); | ||||
1648 | } | ||||
1649 | |||||
1650 | /// \pre Idx < getNumRanges() | ||||
1651 | const CharSourceRange &getRange(unsigned Idx) const { | ||||
1652 | assert(Idx < getNumRanges() && "Invalid diagnostic range index!")(static_cast <bool> (Idx < getNumRanges() && "Invalid diagnostic range index!") ? void (0) : __assert_fail ("Idx < getNumRanges() && \"Invalid diagnostic range index!\"" , "clang/include/clang/Basic/Diagnostic.h", 1652, __extension__ __PRETTY_FUNCTION__)); | ||||
1653 | return DiagObj->DiagStorage.DiagRanges[Idx]; | ||||
1654 | } | ||||
1655 | |||||
1656 | /// Return an array reference for this diagnostic's ranges. | ||||
1657 | ArrayRef<CharSourceRange> getRanges() const { | ||||
1658 | return DiagObj->DiagStorage.DiagRanges; | ||||
1659 | } | ||||
1660 | |||||
1661 | unsigned getNumFixItHints() const { | ||||
1662 | return DiagObj->DiagStorage.FixItHints.size(); | ||||
1663 | } | ||||
1664 | |||||
1665 | const FixItHint &getFixItHint(unsigned Idx) const { | ||||
1666 | assert(Idx < getNumFixItHints() && "Invalid index!")(static_cast <bool> (Idx < getNumFixItHints() && "Invalid index!") ? void (0) : __assert_fail ("Idx < getNumFixItHints() && \"Invalid index!\"" , "clang/include/clang/Basic/Diagnostic.h", 1666, __extension__ __PRETTY_FUNCTION__)); | ||||
1667 | return DiagObj->DiagStorage.FixItHints[Idx]; | ||||
1668 | } | ||||
1669 | |||||
1670 | ArrayRef<FixItHint> getFixItHints() const { | ||||
1671 | return DiagObj->DiagStorage.FixItHints; | ||||
1672 | } | ||||
1673 | |||||
1674 | /// Format this diagnostic into a string, substituting the | ||||
1675 | /// formal arguments into the %0 slots. | ||||
1676 | /// | ||||
1677 | /// The result is appended onto the \p OutStr array. | ||||
1678 | void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const; | ||||
1679 | |||||
1680 | /// Format the given format-string into the output buffer using the | ||||
1681 | /// arguments stored in this diagnostic. | ||||
1682 | void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, | ||||
1683 | SmallVectorImpl<char> &OutStr) const; | ||||
1684 | }; | ||||
1685 | |||||
1686 | /** | ||||
1687 | * Represents a diagnostic in a form that can be retained until its | ||||
1688 | * corresponding source manager is destroyed. | ||||
1689 | */ | ||||
1690 | class StoredDiagnostic { | ||||
1691 | unsigned ID; | ||||
1692 | DiagnosticsEngine::Level Level; | ||||
1693 | FullSourceLoc Loc; | ||||
1694 | std::string Message; | ||||
1695 | std::vector<CharSourceRange> Ranges; | ||||
1696 | std::vector<FixItHint> FixIts; | ||||
1697 | |||||
1698 | public: | ||||
1699 | StoredDiagnostic() = default; | ||||
1700 | StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); | ||||
1701 | StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, | ||||
1702 | StringRef Message); | ||||
1703 | StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, | ||||
1704 | StringRef Message, FullSourceLoc Loc, | ||||
1705 | ArrayRef<CharSourceRange> Ranges, | ||||
1706 | ArrayRef<FixItHint> Fixits); | ||||
1707 | |||||
1708 | /// Evaluates true when this object stores a diagnostic. | ||||
1709 | explicit operator bool() const { return !Message.empty(); } | ||||
1710 | |||||
1711 | unsigned getID() const { return ID; } | ||||
1712 | DiagnosticsEngine::Level getLevel() const { return Level; } | ||||
1713 | const FullSourceLoc &getLocation() const { return Loc; } | ||||
1714 | StringRef getMessage() const { return Message; } | ||||
1715 | |||||
1716 | void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } | ||||
1717 | |||||
1718 | using range_iterator = std::vector<CharSourceRange>::const_iterator; | ||||
1719 | |||||
1720 | range_iterator range_begin() const { return Ranges.begin(); } | ||||
1721 | range_iterator range_end() const { return Ranges.end(); } | ||||
1722 | unsigned range_size() const { return Ranges.size(); } | ||||
1723 | |||||
1724 | ArrayRef<CharSourceRange> getRanges() const { return llvm::ArrayRef(Ranges); } | ||||
1725 | |||||
1726 | using fixit_iterator = std::vector<FixItHint>::const_iterator; | ||||
1727 | |||||
1728 | fixit_iterator fixit_begin() const { return FixIts.begin(); } | ||||
1729 | fixit_iterator fixit_end() const { return FixIts.end(); } | ||||
1730 | unsigned fixit_size() const { return FixIts.size(); } | ||||
1731 | |||||
1732 | ArrayRef<FixItHint> getFixIts() const { return llvm::ArrayRef(FixIts); } | ||||
1733 | }; | ||||
1734 | |||||
1735 | // Simple debug printing of StoredDiagnostic. | ||||
1736 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StoredDiagnostic &); | ||||
1737 | |||||
1738 | /// Abstract interface, implemented by clients of the front-end, which | ||||
1739 | /// formats and prints fully processed diagnostics. | ||||
1740 | class DiagnosticConsumer { | ||||
1741 | protected: | ||||
1742 | unsigned NumWarnings = 0; ///< Number of warnings reported | ||||
1743 | unsigned NumErrors = 0; ///< Number of errors reported | ||||
1744 | |||||
1745 | public: | ||||
1746 | DiagnosticConsumer() = default; | ||||
1747 | virtual ~DiagnosticConsumer(); | ||||
1748 | |||||
1749 | unsigned getNumErrors() const { return NumErrors; } | ||||
1750 | unsigned getNumWarnings() const { return NumWarnings; } | ||||
1751 | virtual void clear() { NumWarnings = NumErrors = 0; } | ||||
1752 | |||||
1753 | /// Callback to inform the diagnostic client that processing | ||||
1754 | /// of a source file is beginning. | ||||
1755 | /// | ||||
1756 | /// Note that diagnostics may be emitted outside the processing of a source | ||||
1757 | /// file, for example during the parsing of command line options. However, | ||||
1758 | /// diagnostics with source range information are required to only be emitted | ||||
1759 | /// in between BeginSourceFile() and EndSourceFile(). | ||||
1760 | /// | ||||
1761 | /// \param LangOpts The language options for the source file being processed. | ||||
1762 | /// \param PP The preprocessor object being used for the source; this is | ||||
1763 | /// optional, e.g., it may not be present when processing AST source files. | ||||
1764 | virtual void BeginSourceFile(const LangOptions &LangOpts, | ||||
1765 | const Preprocessor *PP = nullptr) {} | ||||
1766 | |||||
1767 | /// Callback to inform the diagnostic client that processing | ||||
1768 | /// of a source file has ended. | ||||
1769 | /// | ||||
1770 | /// The diagnostic client should assume that any objects made available via | ||||
1771 | /// BeginSourceFile() are inaccessible. | ||||
1772 | virtual void EndSourceFile() {} | ||||
1773 | |||||
1774 | /// Callback to inform the diagnostic client that processing of all | ||||
1775 | /// source files has ended. | ||||
1776 | virtual void finish() {} | ||||
1777 | |||||
1778 | /// Indicates whether the diagnostics handled by this | ||||
1779 | /// DiagnosticConsumer should be included in the number of diagnostics | ||||
1780 | /// reported by DiagnosticsEngine. | ||||
1781 | /// | ||||
1782 | /// The default implementation returns true. | ||||
1783 | virtual bool IncludeInDiagnosticCounts() const; | ||||
1784 | |||||
1785 | /// Handle this diagnostic, reporting it to the user or | ||||
1786 | /// capturing it to a log as needed. | ||||
1787 | /// | ||||
1788 | /// The default implementation just keeps track of the total number of | ||||
1789 | /// warnings and errors. | ||||
1790 | virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, | ||||
1791 | const Diagnostic &Info); | ||||
1792 | }; | ||||
1793 | |||||
1794 | /// A diagnostic client that ignores all diagnostics. | ||||
1795 | class IgnoringDiagConsumer : public DiagnosticConsumer { | ||||
1796 | virtual void anchor(); | ||||
1797 | |||||
1798 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, | ||||
1799 | const Diagnostic &Info) override { | ||||
1800 | // Just ignore it. | ||||
1801 | } | ||||
1802 | }; | ||||
1803 | |||||
1804 | /// Diagnostic consumer that forwards diagnostics along to an | ||||
1805 | /// existing, already-initialized diagnostic consumer. | ||||
1806 | /// | ||||
1807 | class ForwardingDiagnosticConsumer : public DiagnosticConsumer { | ||||
1808 | DiagnosticConsumer &Target; | ||||
1809 | |||||
1810 | public: | ||||
1811 | ForwardingDiagnosticConsumer(DiagnosticConsumer &Target) : Target(Target) {} | ||||
1812 | ~ForwardingDiagnosticConsumer() override; | ||||
1813 | |||||
1814 | void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, | ||||
1815 | const Diagnostic &Info) override; | ||||
1816 | void clear() override; | ||||
1817 | |||||
1818 | bool IncludeInDiagnosticCounts() const override; | ||||
1819 | }; | ||||
1820 | |||||
1821 | // Struct used for sending info about how a type should be printed. | ||||
1822 | struct TemplateDiffTypes { | ||||
1823 | intptr_t FromType; | ||||
1824 | intptr_t ToType; | ||||
1825 | unsigned PrintTree : 1; | ||||
1826 | unsigned PrintFromType : 1; | ||||
1827 | unsigned ElideType : 1; | ||||
1828 | unsigned ShowColors : 1; | ||||
1829 | |||||
1830 | // The printer sets this variable to true if the template diff was used. | ||||
1831 | unsigned TemplateDiffUsed : 1; | ||||
1832 | }; | ||||
1833 | |||||
1834 | /// Special character that the diagnostic printer will use to toggle the bold | ||||
1835 | /// attribute. The character itself will be not be printed. | ||||
1836 | const char ToggleHighlight = 127; | ||||
1837 | |||||
1838 | /// ProcessWarningOptions - Initialize the diagnostic client and process the | ||||
1839 | /// warning options specified on the command line. | ||||
1840 | void ProcessWarningOptions(DiagnosticsEngine &Diags, | ||||
1841 | const DiagnosticOptions &Opts, | ||||
1842 | bool ReportDiags = true); | ||||
1843 | |||||
1844 | } // namespace clang | ||||
1845 | |||||
1846 | #endif // LLVM_CLANG_BASIC_DIAGNOSTIC_H |