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