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