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/DiagnosticParse.h"
15#include "clang/Basic/PragmaKinds.h"
16#include "clang/Basic/TargetInfo.h"
17#include "clang/Lex/Preprocessor.h"
18#include "clang/Lex/Token.h"
19#include "clang/Parse/LoopHint.h"
20#include "clang/Parse/Parser.h"
21#include "clang/Parse/RAIIObjectsForParser.h"
22#include "clang/Sema/EnterExpressionEvaluationContext.h"
23#include "clang/Sema/Scope.h"
24#include "clang/Sema/SemaCUDA.h"
25#include "clang/Sema/SemaCodeCompletion.h"
26#include "clang/Sema/SemaRISCV.h"
27#include "llvm/ADT/ArrayRef.h"
28#include "llvm/ADT/ScopeExit.h"
29#include "llvm/ADT/StringSwitch.h"
30#include <optional>
31using namespace clang;
32
33namespace {
34
35struct PragmaAlignHandler : public PragmaHandler {
36 explicit PragmaAlignHandler() : PragmaHandler("align") {}
37 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
38 Token &FirstToken) override;
39};
40
41struct PragmaGCCVisibilityHandler : public PragmaHandler {
42 explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {}
43 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
44 Token &FirstToken) override;
45};
46
47struct PragmaOptionsHandler : public PragmaHandler {
48 explicit PragmaOptionsHandler() : PragmaHandler("options") {}
49 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
50 Token &FirstToken) override;
51};
52
53struct PragmaPackHandler : public PragmaHandler {
54 explicit PragmaPackHandler() : PragmaHandler("pack") {}
55 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
56 Token &FirstToken) override;
57};
58
59struct PragmaClangSectionHandler : public PragmaHandler {
60 explicit PragmaClangSectionHandler(Sema &S)
61 : PragmaHandler("section"), Actions(S) {}
62 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
63 Token &FirstToken) override;
64
65private:
66 Sema &Actions;
67};
68
69struct PragmaMSStructHandler : public PragmaHandler {
70 explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {}
71 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
72 Token &FirstToken) override;
73};
74
75struct PragmaUnusedHandler : public PragmaHandler {
76 PragmaUnusedHandler() : PragmaHandler("unused") {}
77 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
78 Token &FirstToken) override;
79};
80
81struct PragmaWeakHandler : public PragmaHandler {
82 explicit PragmaWeakHandler() : PragmaHandler("weak") {}
83 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
84 Token &FirstToken) override;
85};
86
87struct PragmaRedefineExtnameHandler : public PragmaHandler {
88 explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {}
89 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
90 Token &FirstToken) override;
91};
92
93struct PragmaOpenCLExtensionHandler : public PragmaHandler {
94 PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {}
95 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
96 Token &FirstToken) override;
97};
98
99
100struct PragmaFPContractHandler : public PragmaHandler {
101 PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {}
102 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
103 Token &FirstToken) override;
104};
105
106// Pragma STDC implementations.
107
108/// PragmaSTDC_FENV_ACCESSHandler - "\#pragma STDC FENV_ACCESS ...".
109struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler {
110 PragmaSTDC_FENV_ACCESSHandler() : PragmaHandler("FENV_ACCESS") {}
111
112 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
113 Token &Tok) override {
114 Token PragmaName = Tok;
115 if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) {
116 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_fp_ignored)
117 << PragmaName.getIdentifierInfo()->getName();
118 return;
119 }
120 tok::OnOffSwitch OOS;
121 if (PP.LexOnOffSwitch(Result&: OOS))
122 return;
123
124 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
125 1);
126 Toks[0].startToken();
127 Toks[0].setKind(tok::annot_pragma_fenv_access);
128 Toks[0].setLocation(Tok.getLocation());
129 Toks[0].setAnnotationEndLoc(Tok.getLocation());
130 Toks[0].setAnnotationValue(reinterpret_cast<void*>(
131 static_cast<uintptr_t>(OOS)));
132 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
133 /*IsReinject=*/false);
134 }
135};
136
137/// PragmaSTDC_CX_LIMITED_RANGEHandler - "\#pragma STDC CX_LIMITED_RANGE ...".
138struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler {
139 PragmaSTDC_CX_LIMITED_RANGEHandler() : PragmaHandler("CX_LIMITED_RANGE") {}
140
141 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
142 Token &Tok) override {
143 tok::OnOffSwitch OOS;
144 if (PP.LexOnOffSwitch(Result&: OOS))
145 return;
146
147 MutableArrayRef<Token> Toks(
148 PP.getPreprocessorAllocator().Allocate<Token>(Num: 1), 1);
149
150 Toks[0].startToken();
151 Toks[0].setKind(tok::annot_pragma_cx_limited_range);
152 Toks[0].setLocation(Tok.getLocation());
153 Toks[0].setAnnotationEndLoc(Tok.getLocation());
154 Toks[0].setAnnotationValue(
155 reinterpret_cast<void *>(static_cast<uintptr_t>(OOS)));
156 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
157 /*IsReinject=*/false);
158 }
159};
160
161/// Handler for "\#pragma STDC FENV_ROUND ...".
162struct PragmaSTDC_FENV_ROUNDHandler : public PragmaHandler {
163 PragmaSTDC_FENV_ROUNDHandler() : PragmaHandler("FENV_ROUND") {}
164
165 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
166 Token &Tok) override;
167};
168
169/// PragmaSTDC_UnknownHandler - "\#pragma STDC ...".
170struct PragmaSTDC_UnknownHandler : public PragmaHandler {
171 PragmaSTDC_UnknownHandler() = default;
172
173 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
174 Token &UnknownTok) override {
175 // C99 6.10.6p2, unknown forms are not allowed.
176 PP.Diag(Tok: UnknownTok, DiagID: diag::ext_stdc_pragma_ignored);
177 }
178};
179
180struct PragmaFPHandler : public PragmaHandler {
181 PragmaFPHandler() : PragmaHandler("fp") {}
182 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
183 Token &FirstToken) override;
184};
185
186// A pragma handler to be the base of the NoOpenMPHandler and NoOpenACCHandler,
187// which are identical other than the name given to them, and the diagnostic
188// emitted.
189template <diag::kind IgnoredDiag>
190struct PragmaNoSupportHandler : public PragmaHandler {
191 PragmaNoSupportHandler(StringRef Name) : PragmaHandler(Name) {}
192 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
193 Token &FirstToken) override;
194};
195
196struct PragmaNoOpenMPHandler
197 : public PragmaNoSupportHandler<diag::warn_pragma_omp_ignored> {
198 PragmaNoOpenMPHandler() : PragmaNoSupportHandler("omp") {}
199};
200
201struct PragmaNoOpenACCHandler
202 : public PragmaNoSupportHandler<diag::warn_pragma_acc_ignored> {
203 PragmaNoOpenACCHandler() : PragmaNoSupportHandler("acc") {}
204};
205
206// A pragma handler to be the base for the OpenMPHandler and OpenACCHandler,
207// which are identical other than the tokens used for the start/end of a pragma
208// section, and some diagnostics.
209template <tok::TokenKind StartTok, tok::TokenKind EndTok,
210 diag::kind UnexpectedDiag>
211struct PragmaSupportHandler : public PragmaHandler {
212 PragmaSupportHandler(StringRef Name) : PragmaHandler(Name) {}
213 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
214 Token &FirstToken) override;
215};
216
217struct PragmaOpenMPHandler
218 : public PragmaSupportHandler<tok::annot_pragma_openmp,
219 tok::annot_pragma_openmp_end,
220 diag::err_omp_unexpected_directive> {
221 PragmaOpenMPHandler() : PragmaSupportHandler("omp") {}
222};
223
224struct PragmaOpenACCHandler
225 : public PragmaSupportHandler<tok::annot_pragma_openacc,
226 tok::annot_pragma_openacc_end,
227 diag::err_acc_unexpected_directive> {
228 PragmaOpenACCHandler() : PragmaSupportHandler("acc") {}
229};
230
231/// PragmaCommentHandler - "\#pragma comment ...".
232struct PragmaCommentHandler : public PragmaHandler {
233 PragmaCommentHandler(Sema &Actions)
234 : PragmaHandler("comment"), Actions(Actions) {}
235 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
236 Token &FirstToken) override;
237
238private:
239 Sema &Actions;
240 bool SeenCopyrightInTU = false; // TU-scoped
241};
242
243struct PragmaDetectMismatchHandler : public PragmaHandler {
244 PragmaDetectMismatchHandler(Sema &Actions)
245 : PragmaHandler("detect_mismatch"), Actions(Actions) {}
246 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
247 Token &FirstToken) override;
248
249private:
250 Sema &Actions;
251};
252
253struct PragmaFloatControlHandler : public PragmaHandler {
254 PragmaFloatControlHandler(Sema &Actions)
255 : PragmaHandler("float_control") {}
256 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
257 Token &FirstToken) override;
258};
259
260struct PragmaMSPointersToMembers : public PragmaHandler {
261 explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {}
262 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
263 Token &FirstToken) override;
264};
265
266struct PragmaMSVtorDisp : public PragmaHandler {
267 explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {}
268 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
269 Token &FirstToken) override;
270};
271
272struct PragmaMSPragma : public PragmaHandler {
273 explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
274 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
275 Token &FirstToken) override;
276};
277
278/// PragmaOptimizeHandler - "\#pragma clang optimize on/off".
279struct PragmaOptimizeHandler : public PragmaHandler {
280 PragmaOptimizeHandler(Sema &S)
281 : PragmaHandler("optimize"), Actions(S) {}
282 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
283 Token &FirstToken) override;
284
285private:
286 Sema &Actions;
287};
288
289struct PragmaLoopHintHandler : public PragmaHandler {
290 PragmaLoopHintHandler() : PragmaHandler("loop") {}
291 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
292 Token &FirstToken) override;
293};
294
295struct PragmaUnrollHintHandler : public PragmaHandler {
296 PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
297 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
298 Token &FirstToken) override;
299};
300
301struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler {
302 PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {}
303};
304
305// "\#pragma fenv_access (on)".
306struct PragmaMSFenvAccessHandler : public PragmaHandler {
307 PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {}
308 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
309 Token &FirstToken) override {
310 StringRef PragmaName = FirstToken.getIdentifierInfo()->getName();
311 if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) {
312 PP.Diag(Loc: FirstToken.getLocation(), DiagID: diag::warn_pragma_fp_ignored)
313 << PragmaName;
314 return;
315 }
316
317 Token Tok;
318 PP.Lex(Result&: Tok);
319 if (Tok.isNot(K: tok::l_paren)) {
320 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen)
321 << PragmaName;
322 return;
323 }
324 PP.Lex(Result&: Tok); // Consume the l_paren.
325 if (Tok.isNot(K: tok::identifier)) {
326 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_ms_fenv_access);
327 return;
328 }
329 const IdentifierInfo *II = Tok.getIdentifierInfo();
330 tok::OnOffSwitch OOS;
331 if (II->isStr(Str: "on")) {
332 OOS = tok::OOS_ON;
333 PP.Lex(Result&: Tok);
334 } else if (II->isStr(Str: "off")) {
335 OOS = tok::OOS_OFF;
336 PP.Lex(Result&: Tok);
337 } else {
338 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_ms_fenv_access);
339 return;
340 }
341 if (Tok.isNot(K: tok::r_paren)) {
342 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_rparen)
343 << PragmaName;
344 return;
345 }
346 PP.Lex(Result&: Tok); // Consume the r_paren.
347
348 if (Tok.isNot(K: tok::eod)) {
349 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
350 << PragmaName;
351 return;
352 }
353
354 MutableArrayRef<Token> Toks(
355 PP.getPreprocessorAllocator().Allocate<Token>(Num: 1), 1);
356 Toks[0].startToken();
357 Toks[0].setKind(tok::annot_pragma_fenv_access_ms);
358 Toks[0].setLocation(FirstToken.getLocation());
359 Toks[0].setAnnotationEndLoc(Tok.getLocation());
360 Toks[0].setAnnotationValue(
361 reinterpret_cast<void*>(static_cast<uintptr_t>(OOS)));
362 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
363 /*IsReinject=*/false);
364 }
365};
366
367struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler {
368 PragmaForceCUDAHostDeviceHandler(Sema &Actions)
369 : PragmaHandler("force_cuda_host_device"), Actions(Actions) {}
370 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
371 Token &FirstToken) override;
372
373private:
374 Sema &Actions;
375};
376
377/// PragmaAttributeHandler - "\#pragma clang attribute ...".
378struct PragmaAttributeHandler : public PragmaHandler {
379 PragmaAttributeHandler(AttributeFactory &AttrFactory)
380 : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {}
381 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
382 Token &FirstToken) override;
383
384 /// A pool of attributes that were parsed in \#pragma clang attribute.
385 ParsedAttributes AttributesForPragmaAttribute;
386};
387
388struct PragmaMaxTokensHereHandler : public PragmaHandler {
389 PragmaMaxTokensHereHandler() : PragmaHandler("max_tokens_here") {}
390 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
391 Token &FirstToken) override;
392};
393
394struct PragmaMaxTokensTotalHandler : public PragmaHandler {
395 PragmaMaxTokensTotalHandler() : PragmaHandler("max_tokens_total") {}
396 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
397 Token &FirstToken) override;
398};
399
400struct PragmaExportHandler : public PragmaHandler {
401 explicit PragmaExportHandler() : PragmaHandler("export") {}
402 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
403 Token &FirstToken) override;
404};
405
406struct PragmaRISCVHandler : public PragmaHandler {
407 PragmaRISCVHandler(Sema &Actions)
408 : PragmaHandler("riscv"), Actions(Actions) {}
409 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
410 Token &FirstToken) override;
411
412private:
413 Sema &Actions;
414};
415
416void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
417 for (auto &T : Toks)
418 T.setFlag(clang::Token::IsReinjected);
419}
420} // end namespace
421
422void Parser::initializePragmaHandlers() {
423 AlignHandler = std::make_unique<PragmaAlignHandler>();
424 PP.AddPragmaHandler(Handler: AlignHandler.get());
425
426 GCCVisibilityHandler = std::make_unique<PragmaGCCVisibilityHandler>();
427 PP.AddPragmaHandler(Namespace: "GCC", Handler: GCCVisibilityHandler.get());
428
429 OptionsHandler = std::make_unique<PragmaOptionsHandler>();
430 PP.AddPragmaHandler(Handler: OptionsHandler.get());
431
432 PackHandler = std::make_unique<PragmaPackHandler>();
433 PP.AddPragmaHandler(Handler: PackHandler.get());
434
435 MSStructHandler = std::make_unique<PragmaMSStructHandler>();
436 PP.AddPragmaHandler(Handler: MSStructHandler.get());
437
438 UnusedHandler = std::make_unique<PragmaUnusedHandler>();
439 PP.AddPragmaHandler(Handler: UnusedHandler.get());
440
441 WeakHandler = std::make_unique<PragmaWeakHandler>();
442 PP.AddPragmaHandler(Handler: WeakHandler.get());
443
444 RedefineExtnameHandler = std::make_unique<PragmaRedefineExtnameHandler>();
445 PP.AddPragmaHandler(Handler: RedefineExtnameHandler.get());
446
447 FPContractHandler = std::make_unique<PragmaFPContractHandler>();
448 PP.AddPragmaHandler(Namespace: "STDC", Handler: FPContractHandler.get());
449
450 STDCFenvAccessHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>();
451 PP.AddPragmaHandler(Namespace: "STDC", Handler: STDCFenvAccessHandler.get());
452
453 STDCFenvRoundHandler = std::make_unique<PragmaSTDC_FENV_ROUNDHandler>();
454 PP.AddPragmaHandler(Namespace: "STDC", Handler: STDCFenvRoundHandler.get());
455
456 STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>();
457 PP.AddPragmaHandler(Namespace: "STDC", Handler: STDCCXLIMITHandler.get());
458
459 STDCUnknownHandler = std::make_unique<PragmaSTDC_UnknownHandler>();
460 PP.AddPragmaHandler(Namespace: "STDC", Handler: STDCUnknownHandler.get());
461
462 PCSectionHandler = std::make_unique<PragmaClangSectionHandler>(args&: Actions);
463 PP.AddPragmaHandler(Namespace: "clang", Handler: PCSectionHandler.get());
464
465 if (getLangOpts().OpenCL) {
466 OpenCLExtensionHandler = std::make_unique<PragmaOpenCLExtensionHandler>();
467 PP.AddPragmaHandler(Namespace: "OPENCL", Handler: OpenCLExtensionHandler.get());
468
469 PP.AddPragmaHandler(Namespace: "OPENCL", Handler: FPContractHandler.get());
470 }
471 if (getLangOpts().OpenMP)
472 OpenMPHandler = std::make_unique<PragmaOpenMPHandler>();
473 else
474 OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>();
475 PP.AddPragmaHandler(Handler: OpenMPHandler.get());
476
477 if (getLangOpts().OpenACC)
478 OpenACCHandler = std::make_unique<PragmaOpenACCHandler>();
479 else
480 OpenACCHandler = std::make_unique<PragmaNoOpenACCHandler>();
481 PP.AddPragmaHandler(Handler: OpenACCHandler.get());
482
483 if (getLangOpts().MicrosoftExt ||
484 getTargetInfo().getTriple().isOSBinFormatELF() ||
485 getTargetInfo().getTriple().isOSAIX()) {
486 MSCommentHandler = std::make_unique<PragmaCommentHandler>(args&: Actions);
487 PP.AddPragmaHandler(Handler: MSCommentHandler.get());
488 }
489
490 FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(args&: Actions);
491 PP.AddPragmaHandler(Handler: FloatControlHandler.get());
492 if (getLangOpts().MicrosoftExt) {
493 MSDetectMismatchHandler =
494 std::make_unique<PragmaDetectMismatchHandler>(args&: Actions);
495 PP.AddPragmaHandler(Handler: MSDetectMismatchHandler.get());
496 MSPointersToMembers = std::make_unique<PragmaMSPointersToMembers>();
497 PP.AddPragmaHandler(Handler: MSPointersToMembers.get());
498 MSVtorDisp = std::make_unique<PragmaMSVtorDisp>();
499 PP.AddPragmaHandler(Handler: MSVtorDisp.get());
500 MSInitSeg = std::make_unique<PragmaMSPragma>(args: "init_seg");
501 PP.AddPragmaHandler(Handler: MSInitSeg.get());
502 MSDataSeg = std::make_unique<PragmaMSPragma>(args: "data_seg");
503 PP.AddPragmaHandler(Handler: MSDataSeg.get());
504 MSBSSSeg = std::make_unique<PragmaMSPragma>(args: "bss_seg");
505 PP.AddPragmaHandler(Handler: MSBSSSeg.get());
506 MSConstSeg = std::make_unique<PragmaMSPragma>(args: "const_seg");
507 PP.AddPragmaHandler(Handler: MSConstSeg.get());
508 MSCodeSeg = std::make_unique<PragmaMSPragma>(args: "code_seg");
509 PP.AddPragmaHandler(Handler: MSCodeSeg.get());
510 MSSection = std::make_unique<PragmaMSPragma>(args: "section");
511 PP.AddPragmaHandler(Handler: MSSection.get());
512 MSStrictGuardStackCheck =
513 std::make_unique<PragmaMSPragma>(args: "strict_gs_check");
514 PP.AddPragmaHandler(Handler: MSStrictGuardStackCheck.get());
515 MSFunction = std::make_unique<PragmaMSPragma>(args: "function");
516 PP.AddPragmaHandler(Handler: MSFunction.get());
517 MSAllocText = std::make_unique<PragmaMSPragma>(args: "alloc_text");
518 PP.AddPragmaHandler(Handler: MSAllocText.get());
519 MSOptimize = std::make_unique<PragmaMSPragma>(args: "optimize");
520 PP.AddPragmaHandler(Handler: MSOptimize.get());
521 MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
522 PP.AddPragmaHandler(Handler: MSRuntimeChecks.get());
523 MSIntrinsic = std::make_unique<PragmaMSPragma>(args: "intrinsic");
524 PP.AddPragmaHandler(Handler: MSIntrinsic.get());
525 MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
526 PP.AddPragmaHandler(Handler: MSFenvAccess.get());
527 }
528
529 if (getLangOpts().CUDA) {
530 CUDAForceHostDeviceHandler =
531 std::make_unique<PragmaForceCUDAHostDeviceHandler>(args&: Actions);
532 PP.AddPragmaHandler(Namespace: "clang", Handler: CUDAForceHostDeviceHandler.get());
533 }
534
535 OptimizeHandler = std::make_unique<PragmaOptimizeHandler>(args&: Actions);
536 PP.AddPragmaHandler(Namespace: "clang", Handler: OptimizeHandler.get());
537
538 LoopHintHandler = std::make_unique<PragmaLoopHintHandler>();
539 PP.AddPragmaHandler(Namespace: "clang", Handler: LoopHintHandler.get());
540
541 UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>(args: "unroll");
542 PP.AddPragmaHandler(Handler: UnrollHintHandler.get());
543 PP.AddPragmaHandler(Namespace: "GCC", Handler: UnrollHintHandler.get());
544
545 NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>(args: "nounroll");
546 PP.AddPragmaHandler(Handler: NoUnrollHintHandler.get());
547 PP.AddPragmaHandler(Namespace: "GCC", Handler: NoUnrollHintHandler.get());
548
549 UnrollAndJamHintHandler =
550 std::make_unique<PragmaUnrollHintHandler>(args: "unroll_and_jam");
551 PP.AddPragmaHandler(Handler: UnrollAndJamHintHandler.get());
552
553 NoUnrollAndJamHintHandler =
554 std::make_unique<PragmaUnrollHintHandler>(args: "nounroll_and_jam");
555 PP.AddPragmaHandler(Handler: NoUnrollAndJamHintHandler.get());
556
557 FPHandler = std::make_unique<PragmaFPHandler>();
558 PP.AddPragmaHandler(Namespace: "clang", Handler: FPHandler.get());
559
560 AttributePragmaHandler =
561 std::make_unique<PragmaAttributeHandler>(args&: AttrFactory);
562 PP.AddPragmaHandler(Namespace: "clang", Handler: AttributePragmaHandler.get());
563
564 MaxTokensHerePragmaHandler = std::make_unique<PragmaMaxTokensHereHandler>();
565 PP.AddPragmaHandler(Namespace: "clang", Handler: MaxTokensHerePragmaHandler.get());
566
567 MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
568 PP.AddPragmaHandler(Namespace: "clang", Handler: MaxTokensTotalPragmaHandler.get());
569
570 if (getLangOpts().ZOSExt) {
571 ExportHandler = std::make_unique<PragmaExportHandler>();
572 PP.AddPragmaHandler(Handler: ExportHandler.get());
573 }
574
575 if (getTargetInfo().getTriple().isRISCV()) {
576 RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(args&: Actions);
577 PP.AddPragmaHandler(Namespace: "clang", Handler: RISCVPragmaHandler.get());
578 }
579}
580
581void Parser::resetPragmaHandlers() {
582 // Remove the pragma handlers we installed.
583 PP.RemovePragmaHandler(Handler: AlignHandler.get());
584 AlignHandler.reset();
585 PP.RemovePragmaHandler(Namespace: "GCC", Handler: GCCVisibilityHandler.get());
586 GCCVisibilityHandler.reset();
587 PP.RemovePragmaHandler(Handler: OptionsHandler.get());
588 OptionsHandler.reset();
589 PP.RemovePragmaHandler(Handler: PackHandler.get());
590 PackHandler.reset();
591 PP.RemovePragmaHandler(Handler: MSStructHandler.get());
592 MSStructHandler.reset();
593 PP.RemovePragmaHandler(Handler: UnusedHandler.get());
594 UnusedHandler.reset();
595 PP.RemovePragmaHandler(Handler: WeakHandler.get());
596 WeakHandler.reset();
597 PP.RemovePragmaHandler(Handler: RedefineExtnameHandler.get());
598 RedefineExtnameHandler.reset();
599
600 if (getLangOpts().OpenCL) {
601 PP.RemovePragmaHandler(Namespace: "OPENCL", Handler: OpenCLExtensionHandler.get());
602 OpenCLExtensionHandler.reset();
603 PP.RemovePragmaHandler(Namespace: "OPENCL", Handler: FPContractHandler.get());
604 }
605 PP.RemovePragmaHandler(Handler: OpenMPHandler.get());
606 OpenMPHandler.reset();
607
608 PP.RemovePragmaHandler(Handler: OpenACCHandler.get());
609 OpenACCHandler.reset();
610
611 if (getLangOpts().MicrosoftExt ||
612 getTargetInfo().getTriple().isOSBinFormatELF() ||
613 getTargetInfo().getTriple().isOSAIX()) {
614 PP.RemovePragmaHandler(Handler: MSCommentHandler.get());
615 MSCommentHandler.reset();
616 }
617
618 PP.RemovePragmaHandler(Namespace: "clang", Handler: PCSectionHandler.get());
619 PCSectionHandler.reset();
620
621 PP.RemovePragmaHandler(Handler: FloatControlHandler.get());
622 FloatControlHandler.reset();
623 if (getLangOpts().MicrosoftExt) {
624 PP.RemovePragmaHandler(Handler: MSDetectMismatchHandler.get());
625 MSDetectMismatchHandler.reset();
626 PP.RemovePragmaHandler(Handler: MSPointersToMembers.get());
627 MSPointersToMembers.reset();
628 PP.RemovePragmaHandler(Handler: MSVtorDisp.get());
629 MSVtorDisp.reset();
630 PP.RemovePragmaHandler(Handler: MSInitSeg.get());
631 MSInitSeg.reset();
632 PP.RemovePragmaHandler(Handler: MSDataSeg.get());
633 MSDataSeg.reset();
634 PP.RemovePragmaHandler(Handler: MSBSSSeg.get());
635 MSBSSSeg.reset();
636 PP.RemovePragmaHandler(Handler: MSConstSeg.get());
637 MSConstSeg.reset();
638 PP.RemovePragmaHandler(Handler: MSCodeSeg.get());
639 MSCodeSeg.reset();
640 PP.RemovePragmaHandler(Handler: MSSection.get());
641 MSSection.reset();
642 PP.RemovePragmaHandler(Handler: MSStrictGuardStackCheck.get());
643 MSStrictGuardStackCheck.reset();
644 PP.RemovePragmaHandler(Handler: MSFunction.get());
645 MSFunction.reset();
646 PP.RemovePragmaHandler(Handler: MSAllocText.get());
647 MSAllocText.reset();
648 PP.RemovePragmaHandler(Handler: MSRuntimeChecks.get());
649 MSRuntimeChecks.reset();
650 PP.RemovePragmaHandler(Handler: MSIntrinsic.get());
651 MSIntrinsic.reset();
652 PP.RemovePragmaHandler(Handler: MSOptimize.get());
653 MSOptimize.reset();
654 PP.RemovePragmaHandler(Handler: MSFenvAccess.get());
655 MSFenvAccess.reset();
656 }
657
658 if (getLangOpts().CUDA) {
659 PP.RemovePragmaHandler(Namespace: "clang", Handler: CUDAForceHostDeviceHandler.get());
660 CUDAForceHostDeviceHandler.reset();
661 }
662
663 PP.RemovePragmaHandler(Namespace: "STDC", Handler: FPContractHandler.get());
664 FPContractHandler.reset();
665
666 PP.RemovePragmaHandler(Namespace: "STDC", Handler: STDCFenvAccessHandler.get());
667 STDCFenvAccessHandler.reset();
668
669 PP.RemovePragmaHandler(Namespace: "STDC", Handler: STDCFenvRoundHandler.get());
670 STDCFenvRoundHandler.reset();
671
672 PP.RemovePragmaHandler(Namespace: "STDC", Handler: STDCCXLIMITHandler.get());
673 STDCCXLIMITHandler.reset();
674
675 PP.RemovePragmaHandler(Namespace: "STDC", Handler: STDCUnknownHandler.get());
676 STDCUnknownHandler.reset();
677
678 PP.RemovePragmaHandler(Namespace: "clang", Handler: OptimizeHandler.get());
679 OptimizeHandler.reset();
680
681 PP.RemovePragmaHandler(Namespace: "clang", Handler: LoopHintHandler.get());
682 LoopHintHandler.reset();
683
684 PP.RemovePragmaHandler(Handler: UnrollHintHandler.get());
685 PP.RemovePragmaHandler(Namespace: "GCC", Handler: UnrollHintHandler.get());
686 UnrollHintHandler.reset();
687
688 PP.RemovePragmaHandler(Handler: NoUnrollHintHandler.get());
689 PP.RemovePragmaHandler(Namespace: "GCC", Handler: NoUnrollHintHandler.get());
690 NoUnrollHintHandler.reset();
691
692 PP.RemovePragmaHandler(Handler: UnrollAndJamHintHandler.get());
693 UnrollAndJamHintHandler.reset();
694
695 PP.RemovePragmaHandler(Handler: NoUnrollAndJamHintHandler.get());
696 NoUnrollAndJamHintHandler.reset();
697
698 PP.RemovePragmaHandler(Namespace: "clang", Handler: FPHandler.get());
699 FPHandler.reset();
700
701 PP.RemovePragmaHandler(Namespace: "clang", Handler: AttributePragmaHandler.get());
702 AttributePragmaHandler.reset();
703
704 PP.RemovePragmaHandler(Namespace: "clang", Handler: MaxTokensHerePragmaHandler.get());
705 MaxTokensHerePragmaHandler.reset();
706
707 PP.RemovePragmaHandler(Namespace: "clang", Handler: MaxTokensTotalPragmaHandler.get());
708 MaxTokensTotalPragmaHandler.reset();
709
710 if (getLangOpts().ZOSExt) {
711 PP.RemovePragmaHandler(Handler: ExportHandler.get());
712 ExportHandler.reset();
713 }
714
715 if (getTargetInfo().getTriple().isRISCV()) {
716 PP.RemovePragmaHandler(Namespace: "clang", Handler: RISCVPragmaHandler.get());
717 RISCVPragmaHandler.reset();
718 }
719}
720
721void Parser::HandlePragmaUnused() {
722 assert(Tok.is(tok::annot_pragma_unused));
723 SourceLocation UnusedLoc = ConsumeAnnotationToken();
724 Actions.ActOnPragmaUnused(Identifier: Tok, curScope: getCurScope(), PragmaLoc: UnusedLoc);
725 ConsumeToken(); // The argument token.
726}
727
728void Parser::HandlePragmaVisibility() {
729 assert(Tok.is(tok::annot_pragma_vis));
730 const IdentifierInfo *VisType =
731 static_cast<IdentifierInfo *>(Tok.getAnnotationValue());
732 SourceLocation VisLoc = ConsumeAnnotationToken();
733 Actions.ActOnPragmaVisibility(VisType, PragmaLoc: VisLoc);
734}
735
736void Parser::HandlePragmaPack() {
737 assert(Tok.is(tok::annot_pragma_pack));
738 Sema::PragmaPackInfo *Info =
739 static_cast<Sema::PragmaPackInfo *>(Tok.getAnnotationValue());
740 SourceLocation PragmaLoc = Tok.getLocation();
741 ExprResult Alignment;
742 if (Info->Alignment.is(K: tok::numeric_constant)) {
743 Alignment = Actions.ActOnNumericConstant(Tok: Info->Alignment);
744 if (Alignment.isInvalid()) {
745 ConsumeAnnotationToken();
746 return;
747 }
748 }
749 Actions.ActOnPragmaPack(PragmaLoc, Action: Info->Action, SlotLabel: Info->SlotLabel,
750 Alignment: Alignment.get());
751 // Consume the token after processing the pragma to enable pragma-specific
752 // #include warnings.
753 ConsumeAnnotationToken();
754}
755
756void Parser::HandlePragmaMSStruct() {
757 assert(Tok.is(tok::annot_pragma_msstruct));
758 PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>(
759 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
760 Actions.ActOnPragmaMSStruct(Kind);
761 ConsumeAnnotationToken();
762}
763
764void Parser::HandlePragmaAlign() {
765 assert(Tok.is(tok::annot_pragma_align));
766 PragmaOptionsAlignKind Kind = static_cast<PragmaOptionsAlignKind>(
767 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
768 Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc: Tok.getLocation());
769 // Consume the token after processing the pragma to enable pragma-specific
770 // #include warnings.
771 ConsumeAnnotationToken();
772}
773
774void Parser::HandlePragmaDump() {
775 assert(Tok.is(tok::annot_pragma_dump));
776 ConsumeAnnotationToken();
777 if (Tok.is(K: tok::eod)) {
778 PP.Diag(Tok, DiagID: diag::warn_pragma_debug_missing_argument) << "dump";
779 } else if (NextToken().is(K: tok::eod)) {
780 if (Tok.isNot(K: tok::identifier)) {
781 PP.Diag(Tok, DiagID: diag::warn_pragma_debug_unexpected_argument);
782 ConsumeAnyToken();
783 ExpectAndConsume(ExpectedTok: tok::eod);
784 return;
785 }
786 IdentifierInfo *II = Tok.getIdentifierInfo();
787 Actions.ActOnPragmaDump(S: getCurScope(), Loc: Tok.getLocation(), II);
788 ConsumeToken();
789 } else {
790 SourceLocation StartLoc = Tok.getLocation();
791 EnterExpressionEvaluationContext Ctx(
792 Actions, Sema::ExpressionEvaluationContext::Unevaluated);
793 ExprResult E = ParseExpression();
794 if (!E.isUsable() || E.get()->containsErrors()) {
795 // Diagnostics were emitted during parsing. No action needed.
796 } else if (E.get()->getDependence() != ExprDependence::None) {
797 PP.Diag(Loc: StartLoc, DiagID: diag::warn_pragma_debug_dependent_argument)
798 << E.get()->isTypeDependent()
799 << SourceRange(StartLoc, Tok.getLocation());
800 } else {
801 Actions.ActOnPragmaDump(E: E.get());
802 }
803 SkipUntil(T: tok::eod, Flags: StopBeforeMatch);
804 }
805 ExpectAndConsume(ExpectedTok: tok::eod);
806}
807
808void Parser::HandlePragmaWeak() {
809 assert(Tok.is(tok::annot_pragma_weak));
810 SourceLocation PragmaLoc = ConsumeAnnotationToken();
811 Actions.ActOnPragmaWeakID(WeakName: Tok.getIdentifierInfo(), PragmaLoc,
812 WeakNameLoc: Tok.getLocation());
813 ConsumeToken(); // The weak name.
814}
815
816void Parser::HandlePragmaWeakAlias() {
817 assert(Tok.is(tok::annot_pragma_weakalias));
818 SourceLocation PragmaLoc = ConsumeAnnotationToken();
819 IdentifierInfo *WeakName = Tok.getIdentifierInfo();
820 SourceLocation WeakNameLoc = Tok.getLocation();
821 ConsumeToken();
822 IdentifierInfo *AliasName = Tok.getIdentifierInfo();
823 SourceLocation AliasNameLoc = Tok.getLocation();
824 ConsumeToken();
825 Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc,
826 WeakNameLoc, AliasNameLoc);
827
828}
829
830void Parser::HandlePragmaRedefineExtname() {
831 assert(Tok.is(tok::annot_pragma_redefine_extname));
832 SourceLocation RedefLoc = ConsumeAnnotationToken();
833 IdentifierInfo *RedefName = Tok.getIdentifierInfo();
834 SourceLocation RedefNameLoc = Tok.getLocation();
835 ConsumeToken();
836 IdentifierInfo *AliasName = Tok.getIdentifierInfo();
837 SourceLocation AliasNameLoc = Tok.getLocation();
838 ConsumeToken();
839 Actions.ActOnPragmaRedefineExtname(WeakName: RedefName, AliasName, PragmaLoc: RedefLoc,
840 WeakNameLoc: RedefNameLoc, AliasNameLoc);
841}
842
843void Parser::HandlePragmaFPContract() {
844 assert(Tok.is(tok::annot_pragma_fp_contract));
845 tok::OnOffSwitch OOS =
846 static_cast<tok::OnOffSwitch>(
847 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
848
849 LangOptions::FPModeKind FPC;
850 switch (OOS) {
851 case tok::OOS_ON:
852 FPC = LangOptions::FPM_On;
853 break;
854 case tok::OOS_OFF:
855 FPC = LangOptions::FPM_Off;
856 break;
857 case tok::OOS_DEFAULT:
858 // According to ISO C99 standard chapter 7.3.4, the default value
859 // for the pragma is ``off'. '-fcomplex-arithmetic=basic',
860 // '-fcx-limited-range', '-fcx-fortran-rules' and
861 // '-fcomplex-arithmetic=improved' control the default value of these
862 // pragmas.
863 FPC = getLangOpts().getDefaultFPContractMode();
864 break;
865 }
866
867 SourceLocation PragmaLoc = ConsumeAnnotationToken();
868 Actions.ActOnPragmaFPContract(Loc: PragmaLoc, FPC);
869}
870
871void Parser::HandlePragmaFloatControl() {
872 assert(Tok.is(tok::annot_pragma_float_control));
873
874 // The value that is held on the PragmaFloatControlStack encodes
875 // the PragmaFloatControl kind and the MSStackAction kind
876 // into a single 32-bit word. The MsStackAction is the high 16 bits
877 // and the FloatControl is the lower 16 bits. Use shift and bit-and
878 // to decode the parts.
879 uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
880 Sema::PragmaMsStackAction Action =
881 static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
882 PragmaFloatControlKind Kind = PragmaFloatControlKind(Value & 0xFFFF);
883 SourceLocation PragmaLoc = ConsumeAnnotationToken();
884 Actions.ActOnPragmaFloatControl(Loc: PragmaLoc, Action, Value: Kind);
885}
886
887void Parser::HandlePragmaFEnvAccess() {
888 assert(Tok.is(tok::annot_pragma_fenv_access) ||
889 Tok.is(tok::annot_pragma_fenv_access_ms));
890 tok::OnOffSwitch OOS =
891 static_cast<tok::OnOffSwitch>(
892 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
893
894 bool IsEnabled;
895 switch (OOS) {
896 case tok::OOS_ON:
897 IsEnabled = true;
898 break;
899 case tok::OOS_OFF:
900 IsEnabled = false;
901 break;
902 case tok::OOS_DEFAULT: // FIXME: Add this cli option when it makes sense.
903 IsEnabled = false;
904 break;
905 }
906
907 SourceLocation PragmaLoc = ConsumeAnnotationToken();
908 Actions.ActOnPragmaFEnvAccess(Loc: PragmaLoc, IsEnabled);
909}
910
911void Parser::HandlePragmaFEnvRound() {
912 assert(Tok.is(tok::annot_pragma_fenv_round));
913 auto RM = static_cast<llvm::RoundingMode>(
914 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
915
916 SourceLocation PragmaLoc = ConsumeAnnotationToken();
917 Actions.ActOnPragmaFEnvRound(Loc: PragmaLoc, RM);
918}
919
920void Parser::HandlePragmaCXLimitedRange() {
921 assert(Tok.is(tok::annot_pragma_cx_limited_range));
922 tok::OnOffSwitch OOS = static_cast<tok::OnOffSwitch>(
923 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
924
925 LangOptions::ComplexRangeKind Range;
926 switch (OOS) {
927 case tok::OOS_ON:
928 Range = LangOptions::CX_Basic;
929 break;
930 case tok::OOS_OFF:
931 Range = LangOptions::CX_Full;
932 break;
933 case tok::OOS_DEFAULT:
934 // According to ISO C99 standard chapter 7.3.4, the default value
935 // for the pragma is ``off'. -fcomplex-arithmetic controls the default value
936 // of these pragmas.
937 Range = getLangOpts().getComplexRange();
938 break;
939 }
940
941 SourceLocation PragmaLoc = ConsumeAnnotationToken();
942 Actions.ActOnPragmaCXLimitedRange(Loc: PragmaLoc, Range);
943}
944
945StmtResult Parser::HandlePragmaCaptured()
946{
947 assert(Tok.is(tok::annot_pragma_captured));
948 ConsumeAnnotationToken();
949
950 if (Tok.isNot(K: tok::l_brace)) {
951 PP.Diag(Tok, DiagID: diag::err_expected) << tok::l_brace;
952 return StmtError();
953 }
954
955 SourceLocation Loc = Tok.getLocation();
956
957 ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope |
958 Scope::CompoundStmtScope);
959 Actions.ActOnCapturedRegionStart(Loc, CurScope: getCurScope(), Kind: CR_Default,
960 /*NumParams=*/1);
961
962 StmtResult R = ParseCompoundStatement();
963 CapturedRegionScope.Exit();
964
965 if (R.isInvalid()) {
966 Actions.ActOnCapturedRegionError();
967 return StmtError();
968 }
969
970 return Actions.ActOnCapturedRegionEnd(S: R.get());
971}
972
973namespace {
974 enum OpenCLExtState : char {
975 Disable, Enable, Begin, End
976 };
977 typedef std::pair<const IdentifierInfo *, OpenCLExtState> OpenCLExtData;
978}
979
980void Parser::HandlePragmaOpenCLExtension() {
981 assert(Tok.is(tok::annot_pragma_opencl_extension));
982 OpenCLExtData *Data = static_cast<OpenCLExtData*>(Tok.getAnnotationValue());
983 auto State = Data->second;
984 auto Ident = Data->first;
985 SourceLocation NameLoc = Tok.getLocation();
986 ConsumeAnnotationToken();
987
988 auto &Opt = Actions.getOpenCLOptions();
989 auto Name = Ident->getName();
990 // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
991 // overriding all previously issued extension directives, but only if the
992 // behavior is set to disable."
993 if (Name == "all") {
994 if (State == Disable)
995 Opt.disableAll();
996 else
997 PP.Diag(Loc: NameLoc, DiagID: diag::warn_pragma_expected_predicate) << 1;
998 } else if (State == Begin) {
999 if (!Opt.isKnown(Ext: Name) || !Opt.isSupported(Ext: Name, LO: getLangOpts())) {
1000 Opt.support(Ext: Name);
1001 // FIXME: Default behavior of the extension pragma is not defined.
1002 // Therefore, it should never be added by default.
1003 Opt.acceptsPragma(Ext: Name);
1004 }
1005 } else if (State == End) {
1006 // There is no behavior for this directive. We only accept this for
1007 // backward compatibility.
1008 } else if (!Opt.isKnown(Ext: Name) || !Opt.isWithPragma(Ext: Name))
1009 PP.Diag(Loc: NameLoc, DiagID: diag::warn_pragma_unknown_extension) << Ident;
1010 else if (Opt.isSupportedExtension(Ext: Name, LO: getLangOpts()))
1011 Opt.enable(Ext: Name, V: State == Enable);
1012 else if (Opt.isSupportedCoreOrOptionalCore(Ext: Name, LO: getLangOpts()))
1013 PP.Diag(Loc: NameLoc, DiagID: diag::warn_pragma_extension_is_core) << Ident;
1014 else
1015 PP.Diag(Loc: NameLoc, DiagID: diag::warn_pragma_unsupported_extension) << Ident;
1016}
1017
1018void Parser::HandlePragmaMSPointersToMembers() {
1019 assert(Tok.is(tok::annot_pragma_ms_pointers_to_members));
1020 LangOptions::PragmaMSPointersToMembersKind RepresentationMethod =
1021 static_cast<LangOptions::PragmaMSPointersToMembersKind>(
1022 reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()));
1023 SourceLocation PragmaLoc = ConsumeAnnotationToken();
1024 Actions.ActOnPragmaMSPointersToMembers(Kind: RepresentationMethod, PragmaLoc);
1025}
1026
1027void Parser::HandlePragmaMSVtorDisp() {
1028 assert(Tok.is(tok::annot_pragma_ms_vtordisp));
1029 uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue());
1030 Sema::PragmaMsStackAction Action =
1031 static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF);
1032 MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF);
1033 SourceLocation PragmaLoc = ConsumeAnnotationToken();
1034 Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Value: Mode);
1035}
1036
1037void Parser::HandlePragmaMSPragma() {
1038 assert(Tok.is(tok::annot_pragma_ms_pragma));
1039 // Grab the tokens out of the annotation and enter them into the stream.
1040 auto TheTokens =
1041 (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue();
1042 PP.EnterTokenStream(Toks: std::move(TheTokens->first), NumToks: TheTokens->second, DisableMacroExpansion: true,
1043 /*IsReinject=*/true);
1044 SourceLocation PragmaLocation = ConsumeAnnotationToken();
1045 assert(Tok.isAnyIdentifier());
1046 StringRef PragmaName = Tok.getIdentifierInfo()->getName();
1047 PP.Lex(Result&: Tok); // pragma kind
1048
1049 // Figure out which #pragma we're dealing with. The switch has no default
1050 // because lex shouldn't emit the annotation token for unrecognized pragmas.
1051 typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation);
1052 PragmaHandler Handler =
1053 llvm::StringSwitch<PragmaHandler>(PragmaName)
1054 .Case(S: "data_seg", Value: &Parser::HandlePragmaMSSegment)
1055 .Case(S: "bss_seg", Value: &Parser::HandlePragmaMSSegment)
1056 .Case(S: "const_seg", Value: &Parser::HandlePragmaMSSegment)
1057 .Case(S: "code_seg", Value: &Parser::HandlePragmaMSSegment)
1058 .Case(S: "section", Value: &Parser::HandlePragmaMSSection)
1059 .Case(S: "init_seg", Value: &Parser::HandlePragmaMSInitSeg)
1060 .Case(S: "strict_gs_check", Value: &Parser::HandlePragmaMSStrictGuardStackCheck)
1061 .Case(S: "function", Value: &Parser::HandlePragmaMSFunction)
1062 .Case(S: "alloc_text", Value: &Parser::HandlePragmaMSAllocText)
1063 .Case(S: "optimize", Value: &Parser::HandlePragmaMSOptimize)
1064 .Case(S: "intrinsic", Value: &Parser::HandlePragmaMSIntrinsic);
1065
1066 if (!(this->*Handler)(PragmaName, PragmaLocation)) {
1067 // Pragma handling failed, and has been diagnosed. Slurp up the tokens
1068 // until eof (really end of line) to prevent follow-on errors.
1069 while (Tok.isNot(K: tok::eof))
1070 PP.Lex(Result&: Tok);
1071 PP.Lex(Result&: Tok);
1072 }
1073}
1074
1075bool Parser::HandlePragmaMSSection(StringRef PragmaName,
1076 SourceLocation PragmaLocation) {
1077 if (Tok.isNot(K: tok::l_paren)) {
1078 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_lparen) << PragmaName;
1079 return false;
1080 }
1081 PP.Lex(Result&: Tok); // (
1082 // Parsing code for pragma section
1083 if (Tok.isNot(K: tok::string_literal)) {
1084 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_section_name)
1085 << PragmaName;
1086 return false;
1087 }
1088 ExprResult StringResult = ParseStringLiteralExpression();
1089 if (StringResult.isInvalid())
1090 return false; // Already diagnosed.
1091 StringLiteral *SegmentName = cast<StringLiteral>(Val: StringResult.get());
1092 if (SegmentName->getCharByteWidth() != 1) {
1093 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_non_wide_string)
1094 << PragmaName;
1095 return false;
1096 }
1097 int SectionFlags = ASTContext::PSF_Read;
1098 bool SectionFlagsAreDefault = true;
1099 while (Tok.is(K: tok::comma)) {
1100 PP.Lex(Result&: Tok); // ,
1101 // Ignore "long" and "short".
1102 // They are undocumented, but widely used, section attributes which appear
1103 // to do nothing.
1104 if (Tok.is(K: tok::kw_long) || Tok.is(K: tok::kw_short)) {
1105 PP.Lex(Result&: Tok); // long/short
1106 continue;
1107 }
1108
1109 if (!Tok.isAnyIdentifier()) {
1110 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_action_or_r_paren)
1111 << PragmaName;
1112 return false;
1113 }
1114 ASTContext::PragmaSectionFlag Flag =
1115 llvm::StringSwitch<ASTContext::PragmaSectionFlag>(
1116 Tok.getIdentifierInfo()->getName())
1117 .Case(S: "read", Value: ASTContext::PSF_Read)
1118 .Case(S: "write", Value: ASTContext::PSF_Write)
1119 .Case(S: "execute", Value: ASTContext::PSF_Execute)
1120 .Case(S: "shared", Value: ASTContext::PSF_Invalid)
1121 .Case(S: "nopage", Value: ASTContext::PSF_Invalid)
1122 .Case(S: "nocache", Value: ASTContext::PSF_Invalid)
1123 .Case(S: "discard", Value: ASTContext::PSF_Invalid)
1124 .Case(S: "remove", Value: ASTContext::PSF_Invalid)
1125 .Default(Value: ASTContext::PSF_None);
1126 if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) {
1127 PP.Diag(Loc: PragmaLocation, DiagID: Flag == ASTContext::PSF_None
1128 ? diag::warn_pragma_invalid_specific_action
1129 : diag::warn_pragma_unsupported_action)
1130 << PragmaName << Tok.getIdentifierInfo()->getName();
1131 return false;
1132 }
1133 SectionFlags |= Flag;
1134 SectionFlagsAreDefault = false;
1135 PP.Lex(Result&: Tok); // Identifier
1136 }
1137 // If no section attributes are specified, the section will be marked as
1138 // read/write.
1139 if (SectionFlagsAreDefault)
1140 SectionFlags |= ASTContext::PSF_Write;
1141 if (Tok.isNot(K: tok::r_paren)) {
1142 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_rparen) << PragmaName;
1143 return false;
1144 }
1145 PP.Lex(Result&: Tok); // )
1146 if (Tok.isNot(K: tok::eof)) {
1147 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_extra_tokens_at_eol)
1148 << PragmaName;
1149 return false;
1150 }
1151 PP.Lex(Result&: Tok); // eof
1152 Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
1153 return true;
1154}
1155
1156bool Parser::HandlePragmaMSSegment(StringRef PragmaName,
1157 SourceLocation PragmaLocation) {
1158 if (Tok.isNot(K: tok::l_paren)) {
1159 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_lparen) << PragmaName;
1160 return false;
1161 }
1162 PP.Lex(Result&: Tok); // (
1163 Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
1164 StringRef SlotLabel;
1165 if (Tok.isAnyIdentifier()) {
1166 StringRef PushPop = Tok.getIdentifierInfo()->getName();
1167 if (PushPop == "push")
1168 Action = Sema::PSK_Push;
1169 else if (PushPop == "pop")
1170 Action = Sema::PSK_Pop;
1171 else {
1172 PP.Diag(Loc: PragmaLocation,
1173 DiagID: diag::warn_pragma_expected_section_push_pop_or_name)
1174 << PragmaName;
1175 return false;
1176 }
1177 if (Action != Sema::PSK_Reset) {
1178 PP.Lex(Result&: Tok); // push | pop
1179 if (Tok.is(K: tok::comma)) {
1180 PP.Lex(Result&: Tok); // ,
1181 // If we've got a comma, we either need a label or a string.
1182 if (Tok.isAnyIdentifier()) {
1183 SlotLabel = Tok.getIdentifierInfo()->getName();
1184 PP.Lex(Result&: Tok); // identifier
1185 if (Tok.is(K: tok::comma))
1186 PP.Lex(Result&: Tok);
1187 else if (Tok.isNot(K: tok::r_paren)) {
1188 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_punc)
1189 << PragmaName;
1190 return false;
1191 }
1192 }
1193 } else if (Tok.isNot(K: tok::r_paren)) {
1194 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_punc) << PragmaName;
1195 return false;
1196 }
1197 }
1198 }
1199 // Grab the string literal for our section name.
1200 StringLiteral *SegmentName = nullptr;
1201 if (Tok.isNot(K: tok::r_paren)) {
1202 if (Tok.isNot(K: tok::string_literal)) {
1203 unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
1204 diag::warn_pragma_expected_section_name :
1205 diag::warn_pragma_expected_section_label_or_name :
1206 diag::warn_pragma_expected_section_push_pop_or_name;
1207 PP.Diag(Loc: PragmaLocation, DiagID) << PragmaName;
1208 return false;
1209 }
1210 ExprResult StringResult = ParseStringLiteralExpression();
1211 if (StringResult.isInvalid())
1212 return false; // Already diagnosed.
1213 SegmentName = cast<StringLiteral>(Val: StringResult.get());
1214 if (SegmentName->getCharByteWidth() != 1) {
1215 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_non_wide_string)
1216 << PragmaName;
1217 return false;
1218 }
1219 // Setting section "" has no effect
1220 if (SegmentName->getLength())
1221 Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
1222 }
1223 if (Tok.isNot(K: tok::r_paren)) {
1224 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_rparen) << PragmaName;
1225 return false;
1226 }
1227 PP.Lex(Result&: Tok); // )
1228 if (Tok.isNot(K: tok::eof)) {
1229 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_extra_tokens_at_eol)
1230 << PragmaName;
1231 return false;
1232 }
1233 PP.Lex(Result&: Tok); // eof
1234 Actions.ActOnPragmaMSSeg(PragmaLocation, Action, StackSlotLabel: SlotLabel,
1235 SegmentName, PragmaName);
1236 return true;
1237}
1238
1239bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
1240 SourceLocation PragmaLocation) {
1241 if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) {
1242 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_init_seg_unsupported_target);
1243 return false;
1244 }
1245
1246 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
1247 DiagMsg: PragmaName))
1248 return false;
1249
1250 // Parse either the known section names or the string section name.
1251 StringLiteral *SegmentName = nullptr;
1252 if (Tok.isAnyIdentifier()) {
1253 auto *II = Tok.getIdentifierInfo();
1254 StringRef Section = llvm::StringSwitch<StringRef>(II->getName())
1255 .Case(S: "compiler", Value: "\".CRT$XCC\"")
1256 .Case(S: "lib", Value: "\".CRT$XCL\"")
1257 .Case(S: "user", Value: "\".CRT$XCU\"")
1258 .Default(Value: "");
1259
1260 if (!Section.empty()) {
1261 // Pretend the user wrote the appropriate string literal here.
1262 Token Toks[1];
1263 Toks[0].startToken();
1264 Toks[0].setKind(tok::string_literal);
1265 Toks[0].setLocation(Tok.getLocation());
1266 Toks[0].setLiteralData(Section.data());
1267 Toks[0].setLength(Section.size());
1268 SegmentName =
1269 cast<StringLiteral>(Val: Actions.ActOnStringLiteral(StringToks: Toks, UDLScope: nullptr).get());
1270 PP.Lex(Result&: Tok);
1271 }
1272 } else if (Tok.is(K: tok::string_literal)) {
1273 ExprResult StringResult = ParseStringLiteralExpression();
1274 if (StringResult.isInvalid())
1275 return false;
1276 SegmentName = cast<StringLiteral>(Val: StringResult.get());
1277 if (SegmentName->getCharByteWidth() != 1) {
1278 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_non_wide_string)
1279 << PragmaName;
1280 return false;
1281 }
1282 // FIXME: Add support for the '[, func-name]' part of the pragma.
1283 }
1284
1285 if (!SegmentName) {
1286 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_init_seg) << PragmaName;
1287 return false;
1288 }
1289
1290 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
1291 DiagMsg: PragmaName) ||
1292 ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
1293 DiagMsg: PragmaName))
1294 return false;
1295
1296 Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName);
1297 return true;
1298}
1299
1300bool Parser::HandlePragmaMSStrictGuardStackCheck(
1301 StringRef PragmaName, SourceLocation PragmaLocation) {
1302 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
1303 DiagMsg: PragmaName))
1304 return false;
1305
1306 Sema::PragmaMsStackAction Action = Sema::PSK_Set;
1307 if (Tok.is(K: tok::identifier)) {
1308 StringRef PushPop = Tok.getIdentifierInfo()->getName();
1309 if (PushPop == "push") {
1310 PP.Lex(Result&: Tok);
1311 Action = Sema::PSK_Push;
1312 if (ExpectAndConsume(ExpectedTok: tok::comma, Diag: diag::warn_pragma_expected_punc,
1313 DiagMsg: PragmaName))
1314 return false;
1315 } else if (PushPop == "pop") {
1316 PP.Lex(Result&: Tok);
1317 Action = Sema::PSK_Pop;
1318 }
1319 }
1320
1321 bool Value = false;
1322 if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
1323 const IdentifierInfo *II = Tok.getIdentifierInfo();
1324 if (II && II->isStr(Str: "off")) {
1325 PP.Lex(Result&: Tok);
1326 Value = false;
1327 } else if (II && II->isStr(Str: "on")) {
1328 PP.Lex(Result&: Tok);
1329 Value = true;
1330 } else {
1331 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_invalid_action)
1332 << PragmaName;
1333 return false;
1334 }
1335 }
1336
1337 // Finish the pragma: ')' $
1338 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
1339 DiagMsg: PragmaName))
1340 return false;
1341
1342 if (ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
1343 DiagMsg: PragmaName))
1344 return false;
1345
1346 Actions.ActOnPragmaMSStrictGuardStackCheck(PragmaLocation, Action, Value);
1347 return true;
1348}
1349
1350bool Parser::HandlePragmaMSAllocText(StringRef PragmaName,
1351 SourceLocation PragmaLocation) {
1352 Token FirstTok = Tok;
1353 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
1354 DiagMsg: PragmaName))
1355 return false;
1356
1357 StringRef Section;
1358 if (Tok.is(K: tok::string_literal)) {
1359 ExprResult StringResult = ParseStringLiteralExpression();
1360 if (StringResult.isInvalid())
1361 return false; // Already diagnosed.
1362 StringLiteral *SegmentName = cast<StringLiteral>(Val: StringResult.get());
1363 if (SegmentName->getCharByteWidth() != 1) {
1364 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_non_wide_string)
1365 << PragmaName;
1366 return false;
1367 }
1368 Section = SegmentName->getString();
1369 } else if (Tok.is(K: tok::identifier)) {
1370 Section = Tok.getIdentifierInfo()->getName();
1371 PP.Lex(Result&: Tok);
1372 } else {
1373 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_section_name)
1374 << PragmaName;
1375 return false;
1376 }
1377
1378 if (ExpectAndConsume(ExpectedTok: tok::comma, Diag: diag::warn_pragma_expected_comma,
1379 DiagMsg: PragmaName))
1380 return false;
1381
1382 SmallVector<std::tuple<IdentifierInfo *, SourceLocation>> Functions;
1383 while (true) {
1384 if (Tok.isNot(K: tok::identifier)) {
1385 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
1386 << PragmaName;
1387 return false;
1388 }
1389
1390 IdentifierInfo *II = Tok.getIdentifierInfo();
1391 Functions.emplace_back(Args&: II, Args: Tok.getLocation());
1392
1393 PP.Lex(Result&: Tok);
1394 if (Tok.isNot(K: tok::comma))
1395 break;
1396 PP.Lex(Result&: Tok);
1397 }
1398
1399 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
1400 DiagMsg: PragmaName) ||
1401 ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
1402 DiagMsg: PragmaName))
1403 return false;
1404
1405 Actions.ActOnPragmaMSAllocText(PragmaLocation: FirstTok.getLocation(), Section, Functions);
1406 return true;
1407}
1408
1409void Parser::zOSHandlePragmaHelper(tok::TokenKind PragmaKind) {
1410 assert(Tok.is(PragmaKind));
1411
1412 StringRef PragmaName = "export";
1413
1414 using namespace clang::charinfo;
1415 auto *TheTokens = static_cast<std::pair<std::unique_ptr<Token[]>, size_t> *>(
1416 Tok.getAnnotationValue());
1417 PP.EnterTokenStream(Toks: std::move(TheTokens->first), NumToks: TheTokens->second, DisableMacroExpansion: true,
1418 /*IsReinject=*/true);
1419 Tok.setAnnotationValue(nullptr);
1420 ConsumeAnnotationToken();
1421
1422 llvm::scope_exit OnReturn([this]() {
1423 while (Tok.isNot(K: tok::eof))
1424 PP.Lex(Result&: Tok);
1425 PP.Lex(Result&: Tok);
1426 });
1427
1428 do {
1429 PP.Lex(Result&: Tok);
1430 if (Tok.isNot(K: tok::l_paren)) {
1431 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen)
1432 << PragmaName;
1433 return;
1434 }
1435
1436 PP.Lex(Result&: Tok);
1437 if (Tok.isNot(K: tok::identifier)) {
1438 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
1439 << PragmaName;
1440 return;
1441 }
1442
1443 IdentifierInfo *IdentName = Tok.getIdentifierInfo();
1444 SourceLocation IdentNameLoc = Tok.getLocation();
1445 PP.Lex(Result&: Tok);
1446
1447 if (Tok.isNot(K: tok::r_paren)) {
1448 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_rparen)
1449 << PragmaName;
1450 return;
1451 }
1452
1453 PP.Lex(Result&: Tok);
1454 Actions.ActOnPragmaExport(IdentId: IdentName, ExportNameLoc: IdentNameLoc, curScope: getCurScope());
1455
1456 // Because export is also a C++ keyword, we also check for that.
1457 if (Tok.is(K: tok::identifier) || Tok.is(K: tok::kw_export)) {
1458 PragmaName = Tok.getIdentifierInfo()->getName();
1459 if (PragmaName != "export")
1460 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1461 << PragmaName;
1462 } else if (Tok.isNot(K: tok::eof)) {
1463 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1464 << PragmaName;
1465 return;
1466 }
1467 } while (Tok.isNot(K: tok::eof));
1468 return;
1469}
1470
1471void Parser::HandlePragmaExport() {
1472 assert(Tok.is(tok::annot_pragma_export));
1473
1474 zOSHandlePragmaHelper(PragmaKind: tok::annot_pragma_export);
1475}
1476
1477static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
1478 StringRef Str = PragmaName.getIdentifierInfo()->getName();
1479 std::string ClangLoopStr("clang loop ");
1480 if (Str == "loop" && Option.getIdentifierInfo())
1481 ClangLoopStr += Option.getIdentifierInfo()->getName();
1482 return std::string(llvm::StringSwitch<StringRef>(Str)
1483 .Case(S: "loop", Value: ClangLoopStr)
1484 .Case(S: "unroll_and_jam", Value: Str)
1485 .Case(S: "unroll", Value: Str)
1486 .Default(Value: ""));
1487}
1488
1489bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
1490 assert(Tok.is(tok::annot_pragma_loop_hint));
1491 PragmaLoopHintInfo *Info =
1492 static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
1493
1494 IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo();
1495 Hint.PragmaNameLoc = new (Actions.Context)
1496 IdentifierLoc(Info->PragmaName.getLocation(), PragmaNameInfo);
1497
1498 // It is possible that the loop hint has no option identifier, such as
1499 // #pragma unroll(4).
1500 IdentifierInfo *OptionInfo = Info->Option.is(K: tok::identifier)
1501 ? Info->Option.getIdentifierInfo()
1502 : nullptr;
1503 Hint.OptionLoc = new (Actions.Context)
1504 IdentifierLoc(Info->Option.getLocation(), OptionInfo);
1505
1506 llvm::ArrayRef<Token> Toks = Info->Toks;
1507
1508 // Return a valid hint if pragma unroll or nounroll were specified
1509 // without an argument.
1510 auto IsLoopHint =
1511 llvm::StringSwitch<bool>(PragmaNameInfo->getName())
1512 .Cases(CaseStrings: {"unroll", "nounroll", "unroll_and_jam", "nounroll_and_jam"},
1513 Value: true)
1514 .Default(Value: false);
1515
1516 if (Toks.empty() && IsLoopHint) {
1517 ConsumeAnnotationToken();
1518 Hint.Range = Info->PragmaName.getLocation();
1519 return true;
1520 }
1521
1522 // The constant expression is always followed by an eof token, which increases
1523 // the TokSize by 1.
1524 assert(!Toks.empty() &&
1525 "PragmaLoopHintInfo::Toks must contain at least one token.");
1526
1527 // If no option is specified the argument is assumed to be a constant expr.
1528 bool OptionUnroll = false;
1529 bool OptionUnrollAndJam = false;
1530 bool OptionDistribute = false;
1531 bool OptionPipelineDisabled = false;
1532 bool OptionLICMDisabled = false;
1533 bool StateOption = false;
1534 if (OptionInfo) { // Pragma Unroll does not specify an option.
1535 OptionUnroll = OptionInfo->isStr(Str: "unroll");
1536 OptionUnrollAndJam = OptionInfo->isStr(Str: "unroll_and_jam");
1537 OptionDistribute = OptionInfo->isStr(Str: "distribute");
1538 OptionPipelineDisabled = OptionInfo->isStr(Str: "pipeline");
1539 OptionLICMDisabled = OptionInfo->isStr(Str: "licm");
1540 StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
1541 .Case(S: "vectorize", Value: true)
1542 .Case(S: "interleave", Value: true)
1543 .Case(S: "vectorize_predicate", Value: true)
1544 .Default(Value: false) ||
1545 OptionUnroll || OptionUnrollAndJam || OptionDistribute ||
1546 OptionPipelineDisabled || OptionLICMDisabled;
1547 }
1548
1549 bool AssumeSafetyArg = !OptionUnroll && !OptionUnrollAndJam &&
1550 !OptionDistribute && !OptionPipelineDisabled &&
1551 !OptionLICMDisabled;
1552 // Verify loop hint has an argument.
1553 if (Toks[0].is(K: tok::eof)) {
1554 ConsumeAnnotationToken();
1555 Diag(Loc: Toks[0].getLocation(), DiagID: diag::err_pragma_loop_missing_argument)
1556 << /*StateArgument=*/StateOption
1557 << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
1558 << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
1559 return false;
1560 }
1561
1562 // Validate the argument.
1563 if (StateOption) {
1564 ConsumeAnnotationToken();
1565 SourceLocation StateLoc = Toks[0].getLocation();
1566 IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
1567
1568 bool Valid =
1569 StateInfo &&
1570 llvm::StringSwitch<bool>(StateInfo->getName())
1571 .Case(S: "disable", Value: true)
1572 .Case(S: "enable", Value: !OptionPipelineDisabled && !OptionLICMDisabled)
1573 .Case(S: "full", Value: OptionUnroll || OptionUnrollAndJam)
1574 .Case(S: "assume_safety", Value: AssumeSafetyArg)
1575 .Default(Value: false);
1576 if (!Valid) {
1577 if (OptionPipelineDisabled || OptionLICMDisabled) {
1578 Diag(Loc: Toks[0].getLocation(), DiagID: diag::err_pragma_pipeline_invalid_keyword);
1579 } else {
1580 Diag(Loc: Toks[0].getLocation(), DiagID: diag::err_pragma_invalid_keyword)
1581 << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
1582 << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
1583 }
1584 return false;
1585 }
1586 if (Toks.size() > 2)
1587 Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1588 << PragmaLoopHintString(PragmaName: Info->PragmaName, Option: Info->Option);
1589 Hint.StateLoc = new (Actions.Context) IdentifierLoc(StateLoc, StateInfo);
1590 } else if (OptionInfo && OptionInfo->getName() == "vectorize_width") {
1591 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false,
1592 /*IsReinject=*/false);
1593 ConsumeAnnotationToken();
1594
1595 SourceLocation StateLoc = Toks[0].getLocation();
1596 IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
1597 StringRef IsScalableStr = StateInfo ? StateInfo->getName() : "";
1598
1599 // Look for vectorize_width(fixed|scalable)
1600 if (IsScalableStr == "scalable" || IsScalableStr == "fixed") {
1601 PP.Lex(Result&: Tok); // Identifier
1602
1603 if (Toks.size() > 2) {
1604 Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1605 << PragmaLoopHintString(PragmaName: Info->PragmaName, Option: Info->Option);
1606 while (Tok.isNot(K: tok::eof))
1607 ConsumeAnyToken();
1608 }
1609
1610 Hint.StateLoc = new (Actions.Context) IdentifierLoc(StateLoc, StateInfo);
1611
1612 ConsumeToken(); // Consume the constant expression eof terminator.
1613 } else {
1614 // Enter constant expression including eof terminator into token stream.
1615 ExprResult R = ParseConstantExpression();
1616
1617 if (R.isInvalid() && !Tok.is(K: tok::comma))
1618 Diag(Loc: Toks[0].getLocation(),
1619 DiagID: diag::note_pragma_loop_invalid_vectorize_option);
1620
1621 bool Arg2Error = false;
1622 if (Tok.is(K: tok::comma)) {
1623 PP.Lex(Result&: Tok); // ,
1624
1625 StateInfo = Tok.getIdentifierInfo();
1626 IsScalableStr = StateInfo ? StateInfo->getName() : "";
1627
1628 if (IsScalableStr != "scalable" && IsScalableStr != "fixed") {
1629 Diag(Loc: Tok.getLocation(),
1630 DiagID: diag::err_pragma_loop_invalid_vectorize_option);
1631 Arg2Error = true;
1632 } else
1633 Hint.StateLoc =
1634 new (Actions.Context) IdentifierLoc(StateLoc, StateInfo);
1635
1636 PP.Lex(Result&: Tok); // Identifier
1637 }
1638
1639 // Tokens following an error in an ill-formed constant expression will
1640 // remain in the token stream and must be removed.
1641 if (Tok.isNot(K: tok::eof)) {
1642 Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1643 << PragmaLoopHintString(PragmaName: Info->PragmaName, Option: Info->Option);
1644 while (Tok.isNot(K: tok::eof))
1645 ConsumeAnyToken();
1646 }
1647
1648 ConsumeToken(); // Consume the constant expression eof terminator.
1649
1650 if (Arg2Error || R.isInvalid() ||
1651 Actions.CheckLoopHintExpr(E: R.get(), Loc: Toks[0].getLocation(),
1652 /*AllowZero=*/false))
1653 return false;
1654
1655 // Argument is a constant expression with an integer type.
1656 Hint.ValueExpr = R.get();
1657 }
1658 } else {
1659 // Enter constant expression including eof terminator into token stream.
1660 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false,
1661 /*IsReinject=*/false);
1662 ConsumeAnnotationToken();
1663 ExprResult R = ParseConstantExpression();
1664
1665 // Tokens following an error in an ill-formed constant expression will
1666 // remain in the token stream and must be removed.
1667 if (Tok.isNot(K: tok::eof)) {
1668 Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
1669 << PragmaLoopHintString(PragmaName: Info->PragmaName, Option: Info->Option);
1670 while (Tok.isNot(K: tok::eof))
1671 ConsumeAnyToken();
1672 }
1673
1674 ConsumeToken(); // Consume the constant expression eof terminator.
1675
1676 if (R.isInvalid() ||
1677 Actions.CheckLoopHintExpr(E: R.get(), Loc: Toks[0].getLocation(),
1678 /*AllowZero=*/true))
1679 return false;
1680
1681 // Argument is a constant expression with an integer type.
1682 Hint.ValueExpr = R.get();
1683 }
1684
1685 Hint.Range = SourceRange(Info->PragmaName.getLocation(),
1686 Info->Toks.back().getLocation());
1687 return true;
1688}
1689
1690namespace {
1691struct PragmaAttributeInfo {
1692 enum ActionType { Push, Pop, Attribute };
1693 ParsedAttributes &Attributes;
1694 ActionType Action;
1695 const IdentifierInfo *Namespace = nullptr;
1696 ArrayRef<Token> Tokens;
1697
1698 PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {}
1699};
1700
1701#include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc"
1702
1703} // end anonymous namespace
1704
1705static StringRef getIdentifier(const Token &Tok) {
1706 if (Tok.is(K: tok::identifier))
1707 return Tok.getIdentifierInfo()->getName();
1708 const char *S = tok::getKeywordSpelling(Kind: Tok.getKind());
1709 if (!S)
1710 return "";
1711 return S;
1712}
1713
1714static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) {
1715 using namespace attr;
1716 switch (Rule) {
1717#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) \
1718 case Value: \
1719 return IsAbstract;
1720#include "clang/Basic/AttrSubMatchRulesList.inc"
1721 }
1722 llvm_unreachable("Invalid attribute subject match rule");
1723 return false;
1724}
1725
1726static void diagnoseExpectedAttributeSubjectSubRule(
1727 Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
1728 SourceLocation SubRuleLoc) {
1729 auto Diagnostic =
1730 PRef.Diag(Loc: SubRuleLoc,
1731 DiagID: diag::err_pragma_attribute_expected_subject_sub_identifier)
1732 << PrimaryRuleName;
1733 if (const char *SubRules = validAttributeSubjectMatchSubRules(Rule: PrimaryRule))
1734 Diagnostic << /*SubRulesSupported=*/1 << SubRules;
1735 else
1736 Diagnostic << /*SubRulesSupported=*/0;
1737}
1738
1739static void diagnoseUnknownAttributeSubjectSubRule(
1740 Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName,
1741 StringRef SubRuleName, SourceLocation SubRuleLoc) {
1742
1743 auto Diagnostic =
1744 PRef.Diag(Loc: SubRuleLoc, DiagID: diag::err_pragma_attribute_unknown_subject_sub_rule)
1745 << SubRuleName << PrimaryRuleName;
1746 if (const char *SubRules = validAttributeSubjectMatchSubRules(Rule: PrimaryRule))
1747 Diagnostic << /*SubRulesSupported=*/1 << SubRules;
1748 else
1749 Diagnostic << /*SubRulesSupported=*/0;
1750}
1751
1752bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
1753 attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc,
1754 SourceLocation &LastMatchRuleEndLoc) {
1755 bool IsAny = false;
1756 BalancedDelimiterTracker AnyParens(*this, tok::l_paren);
1757 if (getIdentifier(Tok) == "any") {
1758 AnyLoc = ConsumeToken();
1759 IsAny = true;
1760 if (AnyParens.expectAndConsume())
1761 return true;
1762 }
1763
1764 do {
1765 // Parse the subject matcher rule.
1766 StringRef Name = getIdentifier(Tok);
1767 if (Name.empty()) {
1768 Diag(Tok, DiagID: diag::err_pragma_attribute_expected_subject_identifier);
1769 return true;
1770 }
1771 std::pair<std::optional<attr::SubjectMatchRule>,
1772 std::optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
1773 Rule = isAttributeSubjectMatchRule(Name);
1774 if (!Rule.first) {
1775 Diag(Tok, DiagID: diag::err_pragma_attribute_unknown_subject_rule) << Name;
1776 return true;
1777 }
1778 attr::SubjectMatchRule PrimaryRule = *Rule.first;
1779 SourceLocation RuleLoc = ConsumeToken();
1780
1781 BalancedDelimiterTracker Parens(*this, tok::l_paren);
1782 if (isAbstractAttrMatcherRule(Rule: PrimaryRule)) {
1783 if (Parens.expectAndConsume())
1784 return true;
1785 } else if (Parens.consumeOpen()) {
1786 if (!SubjectMatchRules
1787 .insert(
1788 KV: std::make_pair(x&: PrimaryRule, y: SourceRange(RuleLoc, RuleLoc)))
1789 .second)
1790 Diag(Loc: RuleLoc, DiagID: diag::err_pragma_attribute_duplicate_subject)
1791 << Name
1792 << FixItHint::CreateRemoval(RemoveRange: SourceRange(
1793 RuleLoc, Tok.is(K: tok::comma) ? Tok.getLocation() : RuleLoc));
1794 LastMatchRuleEndLoc = RuleLoc;
1795 continue;
1796 }
1797
1798 // Parse the sub-rules.
1799 StringRef SubRuleName = getIdentifier(Tok);
1800 if (SubRuleName.empty()) {
1801 diagnoseExpectedAttributeSubjectSubRule(PRef&: *this, PrimaryRule, PrimaryRuleName: Name,
1802 SubRuleLoc: Tok.getLocation());
1803 return true;
1804 }
1805 attr::SubjectMatchRule SubRule;
1806 if (SubRuleName == "unless") {
1807 SourceLocation SubRuleLoc = ConsumeToken();
1808 BalancedDelimiterTracker Parens(*this, tok::l_paren);
1809 if (Parens.expectAndConsume())
1810 return true;
1811 SubRuleName = getIdentifier(Tok);
1812 if (SubRuleName.empty()) {
1813 diagnoseExpectedAttributeSubjectSubRule(PRef&: *this, PrimaryRule, PrimaryRuleName: Name,
1814 SubRuleLoc);
1815 return true;
1816 }
1817 auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true);
1818 if (!SubRuleOrNone) {
1819 std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")";
1820 diagnoseUnknownAttributeSubjectSubRule(PRef&: *this, PrimaryRule, PrimaryRuleName: Name,
1821 SubRuleName: SubRuleUnlessName, SubRuleLoc);
1822 return true;
1823 }
1824 SubRule = *SubRuleOrNone;
1825 ConsumeToken();
1826 if (Parens.consumeClose())
1827 return true;
1828 } else {
1829 auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false);
1830 if (!SubRuleOrNone) {
1831 diagnoseUnknownAttributeSubjectSubRule(PRef&: *this, PrimaryRule, PrimaryRuleName: Name,
1832 SubRuleName, SubRuleLoc: Tok.getLocation());
1833 return true;
1834 }
1835 SubRule = *SubRuleOrNone;
1836 ConsumeToken();
1837 }
1838 SourceLocation RuleEndLoc = Tok.getLocation();
1839 LastMatchRuleEndLoc = RuleEndLoc;
1840 if (Parens.consumeClose())
1841 return true;
1842 if (!SubjectMatchRules
1843 .insert(KV: std::make_pair(x&: SubRule, y: SourceRange(RuleLoc, RuleEndLoc)))
1844 .second) {
1845 Diag(Loc: RuleLoc, DiagID: diag::err_pragma_attribute_duplicate_subject)
1846 << attr::getSubjectMatchRuleSpelling(Rule: SubRule)
1847 << FixItHint::CreateRemoval(RemoveRange: SourceRange(
1848 RuleLoc, Tok.is(K: tok::comma) ? Tok.getLocation() : RuleEndLoc));
1849 continue;
1850 }
1851 } while (IsAny && TryConsumeToken(Expected: tok::comma));
1852
1853 if (IsAny)
1854 if (AnyParens.consumeClose())
1855 return true;
1856
1857 return false;
1858}
1859
1860namespace {
1861
1862/// Describes the stage at which attribute subject rule parsing was interrupted.
1863enum class MissingAttributeSubjectRulesRecoveryPoint {
1864 Comma,
1865 ApplyTo,
1866 Equals,
1867 Any,
1868 None,
1869};
1870
1871MissingAttributeSubjectRulesRecoveryPoint
1872getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
1873 if (const auto *II = Tok.getIdentifierInfo()) {
1874 if (II->isStr(Str: "apply_to"))
1875 return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
1876 if (II->isStr(Str: "any"))
1877 return MissingAttributeSubjectRulesRecoveryPoint::Any;
1878 }
1879 if (Tok.is(K: tok::equal))
1880 return MissingAttributeSubjectRulesRecoveryPoint::Equals;
1881 return MissingAttributeSubjectRulesRecoveryPoint::None;
1882}
1883
1884/// Creates a diagnostic for the attribute subject rule parsing diagnostic that
1885/// suggests the possible attribute subject rules in a fix-it together with
1886/// any other missing tokens.
1887DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic(
1888 unsigned DiagID, ParsedAttributes &Attrs,
1889 MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) {
1890 SourceLocation Loc = PRef.getEndOfPreviousToken();
1891 if (Loc.isInvalid())
1892 Loc = PRef.getCurToken().getLocation();
1893 auto Diagnostic = PRef.Diag(Loc, DiagID);
1894 std::string FixIt;
1895 MissingAttributeSubjectRulesRecoveryPoint EndPoint =
1896 getAttributeSubjectRulesRecoveryPointForToken(Tok: PRef.getCurToken());
1897 if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma)
1898 FixIt = ", ";
1899 if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo &&
1900 EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo)
1901 FixIt += "apply_to";
1902 if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals &&
1903 EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals)
1904 FixIt += " = ";
1905 SourceRange FixItRange(Loc);
1906 if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) {
1907 // Gather the subject match rules that are supported by the attribute.
1908 // Add all the possible rules initially.
1909 llvm::BitVector IsMatchRuleAvailable(attr::SubjectMatchRule_Last + 1, true);
1910 // Remove the ones that are not supported by any of the attributes.
1911 for (const ParsedAttr &Attribute : Attrs) {
1912 SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> MatchRules;
1913 Attribute.getMatchRules(LangOpts: PRef.getLangOpts(), MatchRules);
1914 llvm::BitVector IsSupported(attr::SubjectMatchRule_Last + 1);
1915 for (const auto &Rule : MatchRules) {
1916 // Ensure that the missing rule is reported in the fix-it only when it's
1917 // supported in the current language mode.
1918 if (!Rule.second)
1919 continue;
1920 IsSupported[Rule.first] = true;
1921 }
1922 IsMatchRuleAvailable &= IsSupported;
1923 }
1924 if (IsMatchRuleAvailable.count() == 0) {
1925 // FIXME: We can emit a "fix-it" with a subject list placeholder when
1926 // placeholders will be supported by the fix-its.
1927 return Diagnostic;
1928 }
1929 FixIt += "any(";
1930 bool NeedsComma = false;
1931 for (unsigned I = 0; I <= attr::SubjectMatchRule_Last; I++) {
1932 if (!IsMatchRuleAvailable[I])
1933 continue;
1934 if (NeedsComma)
1935 FixIt += ", ";
1936 else
1937 NeedsComma = true;
1938 FixIt += attr::getSubjectMatchRuleSpelling(
1939 Rule: static_cast<attr::SubjectMatchRule>(I));
1940 }
1941 FixIt += ")";
1942 // Check if we need to remove the range
1943 PRef.SkipUntil(T: tok::eof, Flags: Parser::StopBeforeMatch);
1944 FixItRange.setEnd(PRef.getCurToken().getLocation());
1945 }
1946 if (FixItRange.getBegin() == FixItRange.getEnd())
1947 Diagnostic << FixItHint::CreateInsertion(InsertionLoc: FixItRange.getBegin(), Code: FixIt);
1948 else
1949 Diagnostic << FixItHint::CreateReplacement(
1950 RemoveRange: CharSourceRange::getCharRange(R: FixItRange), Code: FixIt);
1951 return Diagnostic;
1952}
1953
1954} // end anonymous namespace
1955
1956void Parser::HandlePragmaAttribute() {
1957 assert(Tok.is(tok::annot_pragma_attribute) &&
1958 "Expected #pragma attribute annotation token");
1959 SourceLocation PragmaLoc = Tok.getLocation();
1960 auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue());
1961 if (Info->Action == PragmaAttributeInfo::Pop) {
1962 ConsumeAnnotationToken();
1963 Actions.ActOnPragmaAttributePop(PragmaLoc, Namespace: Info->Namespace);
1964 return;
1965 }
1966 // Parse the actual attribute with its arguments.
1967 assert((Info->Action == PragmaAttributeInfo::Push ||
1968 Info->Action == PragmaAttributeInfo::Attribute) &&
1969 "Unexpected #pragma attribute command");
1970
1971 if (Info->Action == PragmaAttributeInfo::Push && Info->Tokens.empty()) {
1972 ConsumeAnnotationToken();
1973 Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Namespace: Info->Namespace);
1974 return;
1975 }
1976
1977 PP.EnterTokenStream(Toks: Info->Tokens, /*DisableMacroExpansion=*/false,
1978 /*IsReinject=*/false);
1979 ConsumeAnnotationToken();
1980
1981 ParsedAttributes &Attrs = Info->Attributes;
1982 Attrs.clearListOnly();
1983
1984 auto SkipToEnd = [this]() {
1985 SkipUntil(T: tok::eof, Flags: StopBeforeMatch);
1986 ConsumeToken();
1987 };
1988
1989 if ((Tok.is(K: tok::l_square) && NextToken().is(K: tok::l_square)) ||
1990 Tok.isRegularKeywordAttribute()) {
1991 // Parse the CXX11 style attribute.
1992 SourceLocation EndLoc = Tok.getLocation();
1993 ParseCXX11AttributeSpecifier(Attrs, EndLoc: &EndLoc);
1994 } else if (Tok.is(K: tok::kw___attribute)) {
1995 ConsumeToken();
1996 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::err_expected_lparen_after,
1997 DiagMsg: "attribute"))
1998 return SkipToEnd();
1999 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::err_expected_lparen_after, DiagMsg: "("))
2000 return SkipToEnd();
2001
2002 // FIXME: The practical usefulness of completion here is limited because
2003 // we only get here if the line has balanced parens.
2004 if (Tok.is(K: tok::code_completion)) {
2005 cutOffParsing();
2006 // FIXME: suppress completion of unsupported attributes?
2007 Actions.CodeCompletion().CodeCompleteAttribute(
2008 Syntax: AttributeCommonInfo::Syntax::AS_GNU);
2009 return SkipToEnd();
2010 }
2011
2012 // Parse the comma-separated list of attributes.
2013 do {
2014 if (Tok.isNot(K: tok::identifier)) {
2015 Diag(Tok, DiagID: diag::err_pragma_attribute_expected_attribute_name);
2016 SkipToEnd();
2017 return;
2018 }
2019 IdentifierInfo *AttrName = Tok.getIdentifierInfo();
2020 SourceLocation AttrNameLoc = ConsumeToken();
2021
2022 if (Tok.isNot(K: tok::l_paren))
2023 Attrs.addNew(attrName: AttrName, attrRange: AttrNameLoc, scope: AttributeScopeInfo(), args: nullptr, numArgs: 0,
2024 form: ParsedAttr::Form::GNU());
2025 else
2026 ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr,
2027 /*ScopeName=*/nullptr,
2028 /*ScopeLoc=*/SourceLocation(),
2029 Form: ParsedAttr::Form::GNU(),
2030 /*Declarator=*/D: nullptr);
2031 } while (TryConsumeToken(Expected: tok::comma));
2032
2033 if (ExpectAndConsume(ExpectedTok: tok::r_paren))
2034 return SkipToEnd();
2035 if (ExpectAndConsume(ExpectedTok: tok::r_paren))
2036 return SkipToEnd();
2037 } else if (Tok.is(K: tok::kw___declspec)) {
2038 ParseMicrosoftDeclSpecs(Attrs);
2039 } else {
2040 Diag(Tok, DiagID: diag::err_pragma_attribute_expected_attribute_syntax);
2041 if (Tok.getIdentifierInfo()) {
2042 // If we suspect that this is an attribute suggest the use of
2043 // '__attribute__'.
2044 if (ParsedAttr::getParsedKind(
2045 Name: Tok.getIdentifierInfo(), /*ScopeName=*/Scope: nullptr,
2046 SyntaxUsed: ParsedAttr::AS_GNU) != ParsedAttr::UnknownAttribute) {
2047 SourceLocation InsertStartLoc = Tok.getLocation();
2048 ConsumeToken();
2049 if (Tok.is(K: tok::l_paren)) {
2050 ConsumeAnyToken();
2051 SkipUntil(T: tok::r_paren, Flags: StopBeforeMatch);
2052 if (Tok.isNot(K: tok::r_paren))
2053 return SkipToEnd();
2054 }
2055 Diag(Tok, DiagID: diag::note_pragma_attribute_use_attribute_kw)
2056 << FixItHint::CreateInsertion(InsertionLoc: InsertStartLoc, Code: "__attribute__((")
2057 << FixItHint::CreateInsertion(InsertionLoc: Tok.getEndLoc(), Code: "))");
2058 }
2059 }
2060 SkipToEnd();
2061 return;
2062 }
2063
2064 if (Attrs.empty() || Attrs.begin()->isInvalid()) {
2065 SkipToEnd();
2066 return;
2067 }
2068
2069 for (const ParsedAttr &Attribute : Attrs) {
2070 if (!Attribute.isSupportedByPragmaAttribute()) {
2071 Diag(Loc: PragmaLoc, DiagID: diag::err_pragma_attribute_unsupported_attribute)
2072 << Attribute;
2073 SkipToEnd();
2074 return;
2075 }
2076 }
2077
2078 // Parse the subject-list.
2079 if (!TryConsumeToken(Expected: tok::comma)) {
2080 createExpectedAttributeSubjectRulesTokenDiagnostic(
2081 DiagID: diag::err_expected, Attrs,
2082 Point: MissingAttributeSubjectRulesRecoveryPoint::Comma, PRef&: *this)
2083 << tok::comma;
2084 SkipToEnd();
2085 return;
2086 }
2087
2088 if (Tok.isNot(K: tok::identifier)) {
2089 createExpectedAttributeSubjectRulesTokenDiagnostic(
2090 DiagID: diag::err_pragma_attribute_invalid_subject_set_specifier, Attrs,
2091 Point: MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, PRef&: *this);
2092 SkipToEnd();
2093 return;
2094 }
2095 const IdentifierInfo *II = Tok.getIdentifierInfo();
2096 if (!II->isStr(Str: "apply_to")) {
2097 createExpectedAttributeSubjectRulesTokenDiagnostic(
2098 DiagID: diag::err_pragma_attribute_invalid_subject_set_specifier, Attrs,
2099 Point: MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, PRef&: *this);
2100 SkipToEnd();
2101 return;
2102 }
2103 ConsumeToken();
2104
2105 if (!TryConsumeToken(Expected: tok::equal)) {
2106 createExpectedAttributeSubjectRulesTokenDiagnostic(
2107 DiagID: diag::err_expected, Attrs,
2108 Point: MissingAttributeSubjectRulesRecoveryPoint::Equals, PRef&: *this)
2109 << tok::equal;
2110 SkipToEnd();
2111 return;
2112 }
2113
2114 attr::ParsedSubjectMatchRuleSet SubjectMatchRules;
2115 SourceLocation AnyLoc, LastMatchRuleEndLoc;
2116 if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc,
2117 LastMatchRuleEndLoc)) {
2118 SkipToEnd();
2119 return;
2120 }
2121
2122 // Tokens following an ill-formed attribute will remain in the token stream
2123 // and must be removed.
2124 if (Tok.isNot(K: tok::eof)) {
2125 Diag(Tok, DiagID: diag::err_pragma_attribute_extra_tokens_after_attribute);
2126 SkipToEnd();
2127 return;
2128 }
2129
2130 // Consume the eof terminator token.
2131 ConsumeToken();
2132
2133 // Handle a mixed push/attribute by desurging to a push, then an attribute.
2134 if (Info->Action == PragmaAttributeInfo::Push)
2135 Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Namespace: Info->Namespace);
2136
2137 for (ParsedAttr &Attribute : Attrs) {
2138 Actions.ActOnPragmaAttributeAttribute(Attribute, PragmaLoc,
2139 Rules: SubjectMatchRules);
2140 }
2141}
2142
2143// #pragma GCC visibility comes in two variants:
2144// 'push' '(' [visibility] ')'
2145// 'pop'
2146void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
2147 PragmaIntroducer Introducer,
2148 Token &VisTok) {
2149 SourceLocation VisLoc = VisTok.getLocation();
2150
2151 Token Tok;
2152 PP.LexUnexpandedToken(Result&: Tok);
2153
2154 const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
2155
2156 const IdentifierInfo *VisType;
2157 if (PushPop && PushPop->isStr(Str: "pop")) {
2158 VisType = nullptr;
2159 } else if (PushPop && PushPop->isStr(Str: "push")) {
2160 PP.LexUnexpandedToken(Result&: Tok);
2161 if (Tok.isNot(K: tok::l_paren)) {
2162 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen)
2163 << "visibility";
2164 return;
2165 }
2166 PP.LexUnexpandedToken(Result&: Tok);
2167 VisType = Tok.getIdentifierInfo();
2168 if (!VisType) {
2169 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2170 << "visibility";
2171 return;
2172 }
2173 PP.LexUnexpandedToken(Result&: Tok);
2174 if (Tok.isNot(K: tok::r_paren)) {
2175 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_rparen)
2176 << "visibility";
2177 return;
2178 }
2179 } else {
2180 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2181 << "visibility";
2182 return;
2183 }
2184 SourceLocation EndLoc = Tok.getLocation();
2185 PP.LexUnexpandedToken(Result&: Tok);
2186 if (Tok.isNot(K: tok::eod)) {
2187 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
2188 << "visibility";
2189 return;
2190 }
2191
2192 auto Toks = std::make_unique<Token[]>(num: 1);
2193 Toks[0].startToken();
2194 Toks[0].setKind(tok::annot_pragma_vis);
2195 Toks[0].setLocation(VisLoc);
2196 Toks[0].setAnnotationEndLoc(EndLoc);
2197 Toks[0].setAnnotationValue(
2198 const_cast<void *>(static_cast<const void *>(VisType)));
2199 PP.EnterTokenStream(Toks: std::move(Toks), NumToks: 1, /*DisableMacroExpansion=*/true,
2200 /*IsReinject=*/false);
2201}
2202
2203// #pragma pack(...) comes in the following delicious flavors:
2204// pack '(' [integer] ')'
2205// pack '(' 'show' ')'
2206// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
2207// pack '(' 'packed' | 'full' | 'twobyte' | 'reset' ')' with -fzos-extensions
2208void PragmaPackHandler::HandlePragma(Preprocessor &PP,
2209 PragmaIntroducer Introducer,
2210 Token &PackTok) {
2211 SourceLocation PackLoc = PackTok.getLocation();
2212
2213 Token Tok;
2214 PP.Lex(Result&: Tok);
2215 if (Tok.isNot(K: tok::l_paren)) {
2216 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen) << "pack";
2217 return;
2218 }
2219
2220 Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
2221 StringRef SlotLabel;
2222 Token Alignment;
2223 Alignment.startToken();
2224 PP.Lex(Result&: Tok);
2225 if (Tok.is(K: tok::numeric_constant)) {
2226 Alignment = Tok;
2227
2228 PP.Lex(Result&: Tok);
2229
2230 // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting
2231 // the push/pop stack.
2232 // In Apple gcc/XL, #pragma pack(4) is equivalent to #pragma pack(push, 4)
2233 Action = (PP.getLangOpts().ApplePragmaPack || PP.getLangOpts().XLPragmaPack)
2234 ? Sema::PSK_Push_Set
2235 : Sema::PSK_Set;
2236 } else if (Tok.is(K: tok::identifier)) {
2237 // Map pragma pack options to pack (integer).
2238 auto MapPack = [&](const char *Literal) {
2239 Action = Sema::PSK_Push_Set;
2240 Alignment = Tok;
2241 Alignment.setKind(tok::numeric_constant);
2242 Alignment.setLiteralData(Literal);
2243 Alignment.setLength(1);
2244 };
2245
2246 const IdentifierInfo *II = Tok.getIdentifierInfo();
2247 if (II->isStr(Str: "show")) {
2248 Action = Sema::PSK_Show;
2249 PP.Lex(Result&: Tok);
2250 } else if (II->isStr(Str: "packed") && PP.getLangOpts().ZOSExt) {
2251 // #pragma pack(packed) is the same as #pragma pack(1)
2252 MapPack("1");
2253 PP.Lex(Result&: Tok);
2254 } else if (II->isStr(Str: "full") && PP.getLangOpts().ZOSExt) {
2255 // #pragma pack(full) is the same as #pragma pack(4)
2256 MapPack("4");
2257 PP.Lex(Result&: Tok);
2258 } else if (II->isStr(Str: "twobyte") && PP.getLangOpts().ZOSExt) {
2259 // #pragma pack(twobyte) is the same as #pragma pack(2)
2260 MapPack("2");
2261 PP.Lex(Result&: Tok);
2262 } else if (II->isStr(Str: "reset") && PP.getLangOpts().ZOSExt) {
2263 // #pragma pack(reset) is the same as #pragma pack(pop) on XL
2264 Action = Sema::PSK_Pop;
2265 PP.Lex(Result&: Tok);
2266 } else {
2267 if (II->isStr(Str: "push")) {
2268 Action = Sema::PSK_Push;
2269 } else if (II->isStr(Str: "pop")) {
2270 Action = Sema::PSK_Pop;
2271 } else {
2272 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_invalid_action) << "pack";
2273 return;
2274 }
2275 PP.Lex(Result&: Tok);
2276
2277 if (Tok.is(K: tok::comma)) {
2278 PP.Lex(Result&: Tok);
2279
2280 if (Tok.is(K: tok::numeric_constant)) {
2281 Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
2282 Alignment = Tok;
2283
2284 PP.Lex(Result&: Tok);
2285 } else if (Tok.is(K: tok::identifier)) {
2286 SlotLabel = Tok.getIdentifierInfo()->getName();
2287 PP.Lex(Result&: Tok);
2288
2289 if (Tok.is(K: tok::comma)) {
2290 PP.Lex(Result&: Tok);
2291
2292 if (Tok.isNot(K: tok::numeric_constant)) {
2293 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_pack_malformed);
2294 return;
2295 }
2296
2297 Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
2298 Alignment = Tok;
2299
2300 PP.Lex(Result&: Tok);
2301 }
2302 } else {
2303 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_pack_malformed);
2304 return;
2305 }
2306 }
2307 }
2308 } else if (PP.getLangOpts().ApplePragmaPack ||
2309 PP.getLangOpts().XLPragmaPack) {
2310 // In MSVC/gcc, #pragma pack() resets the alignment without affecting
2311 // the push/pop stack.
2312 // In Apple gcc and IBM XL, #pragma pack() is equivalent to #pragma
2313 // pack(pop).
2314 Action = Sema::PSK_Pop;
2315 }
2316
2317 if (Tok.isNot(K: tok::r_paren)) {
2318 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_rparen) << "pack";
2319 return;
2320 }
2321
2322 SourceLocation RParenLoc = Tok.getLocation();
2323 PP.Lex(Result&: Tok);
2324 if (Tok.isNot(K: tok::eod)) {
2325 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol) << "pack";
2326 return;
2327 }
2328
2329 Sema::PragmaPackInfo *Info =
2330 PP.getPreprocessorAllocator().Allocate<Sema::PragmaPackInfo>(Num: 1);
2331 Info->Action = Action;
2332 Info->SlotLabel = SlotLabel;
2333 Info->Alignment = Alignment;
2334
2335 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
2336 1);
2337 Toks[0].startToken();
2338 Toks[0].setKind(tok::annot_pragma_pack);
2339 Toks[0].setLocation(PackLoc);
2340 Toks[0].setAnnotationEndLoc(RParenLoc);
2341 Toks[0].setAnnotationValue(static_cast<void*>(Info));
2342 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2343 /*IsReinject=*/false);
2344}
2345
2346// #pragma ms_struct on
2347// #pragma ms_struct off
2348void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
2349 PragmaIntroducer Introducer,
2350 Token &MSStructTok) {
2351 PragmaMSStructKind Kind = PMSST_OFF;
2352
2353 Token Tok;
2354 PP.Lex(Result&: Tok);
2355 if (Tok.isNot(K: tok::identifier)) {
2356 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_ms_struct);
2357 return;
2358 }
2359 SourceLocation EndLoc = Tok.getLocation();
2360 const IdentifierInfo *II = Tok.getIdentifierInfo();
2361 if (II->isStr(Str: "on")) {
2362 Kind = PMSST_ON;
2363 PP.Lex(Result&: Tok);
2364 }
2365 else if (II->isStr(Str: "off") || II->isStr(Str: "reset"))
2366 PP.Lex(Result&: Tok);
2367 else {
2368 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_ms_struct);
2369 return;
2370 }
2371
2372 if (Tok.isNot(K: tok::eod)) {
2373 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
2374 << "ms_struct";
2375 return;
2376 }
2377
2378 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
2379 1);
2380 Toks[0].startToken();
2381 Toks[0].setKind(tok::annot_pragma_msstruct);
2382 Toks[0].setLocation(MSStructTok.getLocation());
2383 Toks[0].setAnnotationEndLoc(EndLoc);
2384 Toks[0].setAnnotationValue(reinterpret_cast<void*>(
2385 static_cast<uintptr_t>(Kind)));
2386 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2387 /*IsReinject=*/false);
2388}
2389
2390// #pragma clang section bss="abc" data="" rodata="def" text="" relro=""
2391void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
2392 PragmaIntroducer Introducer,
2393 Token &FirstToken) {
2394
2395 Token Tok;
2396 auto SecKind = PragmaClangSectionKind::Invalid;
2397
2398 PP.Lex(Result&: Tok); // eat 'section'
2399 while (Tok.isNot(K: tok::eod)) {
2400 if (Tok.isNot(K: tok::identifier)) {
2401 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_expected_clang_section_name) << "clang section";
2402 return;
2403 }
2404
2405 const IdentifierInfo *SecType = Tok.getIdentifierInfo();
2406 if (SecType->isStr(Str: "bss"))
2407 SecKind = PragmaClangSectionKind::BSS;
2408 else if (SecType->isStr(Str: "data"))
2409 SecKind = PragmaClangSectionKind::Data;
2410 else if (SecType->isStr(Str: "rodata"))
2411 SecKind = PragmaClangSectionKind::Rodata;
2412 else if (SecType->isStr(Str: "relro"))
2413 SecKind = PragmaClangSectionKind::Relro;
2414 else if (SecType->isStr(Str: "text"))
2415 SecKind = PragmaClangSectionKind::Text;
2416 else {
2417 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_expected_clang_section_name) << "clang section";
2418 return;
2419 }
2420
2421 SourceLocation PragmaLocation = Tok.getLocation();
2422 PP.Lex(Result&: Tok); // eat ['bss'|'data'|'rodata'|'text']
2423 if (Tok.isNot(K: tok::equal)) {
2424 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_clang_section_expected_equal)
2425 << SecKind;
2426 return;
2427 }
2428
2429 std::string SecName;
2430 if (!PP.LexStringLiteral(Result&: Tok, String&: SecName, DiagnosticTag: "pragma clang section", AllowMacroExpansion: false))
2431 return;
2432
2433 Actions.ActOnPragmaClangSection(PragmaLoc: PragmaLocation,
2434 Action: (SecName.size()
2435 ? PragmaClangSectionAction::Set
2436 : PragmaClangSectionAction::Clear),
2437 SecKind, SecName);
2438 }
2439}
2440
2441// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
2442// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
2443// #pragma 'align' '(' {'native','natural','mac68k','power','reset'} ')'
2444static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok,
2445 bool IsOptions) {
2446 Token Tok;
2447
2448 if (IsOptions) {
2449 PP.Lex(Result&: Tok);
2450 if (Tok.isNot(K: tok::identifier) ||
2451 !Tok.getIdentifierInfo()->isStr(Str: "align")) {
2452 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_options_expected_align);
2453 return;
2454 }
2455 }
2456
2457 PP.Lex(Result&: Tok);
2458 if (PP.getLangOpts().XLPragmaPack) {
2459 if (Tok.isNot(K: tok::l_paren)) {
2460 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen) << "align";
2461 return;
2462 }
2463 } else if (Tok.isNot(K: tok::equal)) {
2464 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_align_expected_equal)
2465 << IsOptions;
2466 return;
2467 }
2468
2469 PP.Lex(Result&: Tok);
2470 if (Tok.isNot(K: tok::identifier)) {
2471 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2472 << (IsOptions ? "options" : "align");
2473 return;
2474 }
2475
2476 PragmaOptionsAlignKind Kind = PragmaOptionsAlignKind::Natural;
2477 const IdentifierInfo *II = Tok.getIdentifierInfo();
2478 if (II->isStr(Str: "native"))
2479 Kind = PragmaOptionsAlignKind::Native;
2480 else if (II->isStr(Str: "natural"))
2481 Kind = PragmaOptionsAlignKind::Natural;
2482 else if (II->isStr(Str: "packed"))
2483 Kind = PragmaOptionsAlignKind::Packed;
2484 else if (II->isStr(Str: "power"))
2485 Kind = PragmaOptionsAlignKind::Power;
2486 else if (II->isStr(Str: "mac68k"))
2487 Kind = PragmaOptionsAlignKind::Mac68k;
2488 else if (II->isStr(Str: "reset"))
2489 Kind = PragmaOptionsAlignKind::Reset;
2490 else {
2491 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_align_invalid_option)
2492 << IsOptions;
2493 return;
2494 }
2495
2496 if (PP.getLangOpts().XLPragmaPack) {
2497 PP.Lex(Result&: Tok);
2498 if (Tok.isNot(K: tok::r_paren)) {
2499 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_rparen) << "align";
2500 return;
2501 }
2502 }
2503
2504 SourceLocation EndLoc = Tok.getLocation();
2505 PP.Lex(Result&: Tok);
2506 if (Tok.isNot(K: tok::eod)) {
2507 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
2508 << (IsOptions ? "options" : "align");
2509 return;
2510 }
2511
2512 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
2513 1);
2514 Toks[0].startToken();
2515 Toks[0].setKind(tok::annot_pragma_align);
2516 Toks[0].setLocation(FirstTok.getLocation());
2517 Toks[0].setAnnotationEndLoc(EndLoc);
2518 Toks[0].setAnnotationValue(reinterpret_cast<void*>(
2519 static_cast<uintptr_t>(Kind)));
2520 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2521 /*IsReinject=*/false);
2522}
2523
2524void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
2525 PragmaIntroducer Introducer,
2526 Token &AlignTok) {
2527 ParseAlignPragma(PP, FirstTok&: AlignTok, /*IsOptions=*/false);
2528}
2529
2530void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
2531 PragmaIntroducer Introducer,
2532 Token &OptionsTok) {
2533 ParseAlignPragma(PP, FirstTok&: OptionsTok, /*IsOptions=*/true);
2534}
2535
2536// #pragma unused(identifier)
2537void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
2538 PragmaIntroducer Introducer,
2539 Token &UnusedTok) {
2540 // FIXME: Should we be expanding macros here? My guess is no.
2541 SourceLocation UnusedLoc = UnusedTok.getLocation();
2542
2543 // Lex the left '('.
2544 Token Tok;
2545 PP.Lex(Result&: Tok);
2546 if (Tok.isNot(K: tok::l_paren)) {
2547 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_lparen) << "unused";
2548 return;
2549 }
2550
2551 // Lex the declaration reference(s).
2552 SmallVector<Token, 5> Identifiers;
2553 SourceLocation RParenLoc;
2554 bool LexID = true;
2555
2556 while (true) {
2557 PP.Lex(Result&: Tok);
2558
2559 if (LexID) {
2560 if (Tok.is(K: tok::identifier)) {
2561 Identifiers.push_back(Elt: Tok);
2562 LexID = false;
2563 continue;
2564 }
2565
2566 // Illegal token!
2567 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_unused_expected_var);
2568 return;
2569 }
2570
2571 // We are execting a ')' or a ','.
2572 if (Tok.is(K: tok::comma)) {
2573 LexID = true;
2574 continue;
2575 }
2576
2577 if (Tok.is(K: tok::r_paren)) {
2578 RParenLoc = Tok.getLocation();
2579 break;
2580 }
2581
2582 // Illegal token!
2583 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_punc) << "unused";
2584 return;
2585 }
2586
2587 PP.Lex(Result&: Tok);
2588 if (Tok.isNot(K: tok::eod)) {
2589 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol) <<
2590 "unused";
2591 return;
2592 }
2593
2594 // Verify that we have a location for the right parenthesis.
2595 assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
2596 assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
2597
2598 // For each identifier token, insert into the token stream a
2599 // annot_pragma_unused token followed by the identifier token.
2600 // This allows us to cache a "#pragma unused" that occurs inside an inline
2601 // C++ member function.
2602
2603 MutableArrayRef<Token> Toks(
2604 PP.getPreprocessorAllocator().Allocate<Token>(Num: 2 * Identifiers.size()),
2605 2 * Identifiers.size());
2606 for (unsigned i=0; i != Identifiers.size(); i++) {
2607 Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1];
2608 pragmaUnusedTok.startToken();
2609 pragmaUnusedTok.setKind(tok::annot_pragma_unused);
2610 pragmaUnusedTok.setLocation(UnusedLoc);
2611 idTok = Identifiers[i];
2612 }
2613 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2614 /*IsReinject=*/false);
2615}
2616
2617// #pragma weak identifier
2618// #pragma weak identifier '=' identifier
2619void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
2620 PragmaIntroducer Introducer,
2621 Token &WeakTok) {
2622 SourceLocation WeakLoc = WeakTok.getLocation();
2623
2624 Token Tok;
2625 PP.Lex(Result&: Tok);
2626 if (Tok.isNot(K: tok::identifier)) {
2627 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier) << "weak";
2628 return;
2629 }
2630
2631 Token WeakName = Tok;
2632 bool HasAlias = false;
2633 Token AliasName;
2634
2635 PP.Lex(Result&: Tok);
2636 if (Tok.is(K: tok::equal)) {
2637 HasAlias = true;
2638 PP.Lex(Result&: Tok);
2639 if (Tok.isNot(K: tok::identifier)) {
2640 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2641 << "weak";
2642 return;
2643 }
2644 AliasName = Tok;
2645 PP.Lex(Result&: Tok);
2646 }
2647
2648 if (Tok.isNot(K: tok::eod)) {
2649 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol) << "weak";
2650 return;
2651 }
2652
2653 if (HasAlias) {
2654 MutableArrayRef<Token> Toks(
2655 PP.getPreprocessorAllocator().Allocate<Token>(Num: 3), 3);
2656 Token &pragmaUnusedTok = Toks[0];
2657 pragmaUnusedTok.startToken();
2658 pragmaUnusedTok.setKind(tok::annot_pragma_weakalias);
2659 pragmaUnusedTok.setLocation(WeakLoc);
2660 pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation());
2661 Toks[1] = WeakName;
2662 Toks[2] = AliasName;
2663 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2664 /*IsReinject=*/false);
2665 } else {
2666 MutableArrayRef<Token> Toks(
2667 PP.getPreprocessorAllocator().Allocate<Token>(Num: 2), 2);
2668 Token &pragmaUnusedTok = Toks[0];
2669 pragmaUnusedTok.startToken();
2670 pragmaUnusedTok.setKind(tok::annot_pragma_weak);
2671 pragmaUnusedTok.setLocation(WeakLoc);
2672 pragmaUnusedTok.setAnnotationEndLoc(WeakLoc);
2673 Toks[1] = WeakName;
2674 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2675 /*IsReinject=*/false);
2676 }
2677}
2678
2679// #pragma redefine_extname identifier identifier
2680void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP,
2681 PragmaIntroducer Introducer,
2682 Token &RedefToken) {
2683 SourceLocation RedefLoc = RedefToken.getLocation();
2684
2685 Token Tok;
2686 PP.Lex(Result&: Tok);
2687 if (Tok.isNot(K: tok::identifier)) {
2688 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier) <<
2689 "redefine_extname";
2690 return;
2691 }
2692
2693 Token RedefName = Tok;
2694 PP.Lex(Result&: Tok);
2695
2696 if (Tok.isNot(K: tok::identifier)) {
2697 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2698 << "redefine_extname";
2699 return;
2700 }
2701
2702 Token AliasName = Tok;
2703 PP.Lex(Result&: Tok);
2704
2705 if (Tok.isNot(K: tok::eod)) {
2706 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol) <<
2707 "redefine_extname";
2708 return;
2709 }
2710
2711 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 3),
2712 3);
2713 Token &pragmaRedefTok = Toks[0];
2714 pragmaRedefTok.startToken();
2715 pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname);
2716 pragmaRedefTok.setLocation(RedefLoc);
2717 pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation());
2718 Toks[1] = RedefName;
2719 Toks[2] = AliasName;
2720 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2721 /*IsReinject=*/false);
2722}
2723
2724void PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
2725 PragmaIntroducer Introducer,
2726 Token &Tok) {
2727 tok::OnOffSwitch OOS;
2728 if (PP.LexOnOffSwitch(Result&: OOS))
2729 return;
2730
2731 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
2732 1);
2733 Toks[0].startToken();
2734 Toks[0].setKind(tok::annot_pragma_fp_contract);
2735 Toks[0].setLocation(Tok.getLocation());
2736 Toks[0].setAnnotationEndLoc(Tok.getLocation());
2737 Toks[0].setAnnotationValue(reinterpret_cast<void*>(
2738 static_cast<uintptr_t>(OOS)));
2739 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2740 /*IsReinject=*/false);
2741}
2742
2743void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
2744 PragmaIntroducer Introducer,
2745 Token &Tok) {
2746 PP.LexUnexpandedToken(Result&: Tok);
2747 if (Tok.isNot(K: tok::identifier)) {
2748 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier) <<
2749 "OPENCL";
2750 return;
2751 }
2752 IdentifierInfo *Ext = Tok.getIdentifierInfo();
2753 SourceLocation NameLoc = Tok.getLocation();
2754
2755 PP.Lex(Result&: Tok);
2756 if (Tok.isNot(K: tok::colon)) {
2757 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_colon) << Ext;
2758 return;
2759 }
2760
2761 PP.Lex(Result&: Tok);
2762 if (Tok.isNot(K: tok::identifier)) {
2763 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_predicate) << 0;
2764 return;
2765 }
2766 IdentifierInfo *Pred = Tok.getIdentifierInfo();
2767
2768 OpenCLExtState State;
2769 if (Pred->isStr(Str: "enable")) {
2770 State = Enable;
2771 } else if (Pred->isStr(Str: "disable")) {
2772 State = Disable;
2773 } else if (Pred->isStr(Str: "begin"))
2774 State = Begin;
2775 else if (Pred->isStr(Str: "end"))
2776 State = End;
2777 else {
2778 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_predicate)
2779 << Ext->isStr(Str: "all");
2780 return;
2781 }
2782 SourceLocation StateLoc = Tok.getLocation();
2783
2784 PP.Lex(Result&: Tok);
2785 if (Tok.isNot(K: tok::eod)) {
2786 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol) <<
2787 "OPENCL EXTENSION";
2788 return;
2789 }
2790
2791 auto Info = PP.getPreprocessorAllocator().Allocate<OpenCLExtData>(Num: 1);
2792 Info->first = Ext;
2793 Info->second = State;
2794 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
2795 1);
2796 Toks[0].startToken();
2797 Toks[0].setKind(tok::annot_pragma_opencl_extension);
2798 Toks[0].setLocation(NameLoc);
2799 Toks[0].setAnnotationValue(static_cast<void*>(Info));
2800 Toks[0].setAnnotationEndLoc(StateLoc);
2801 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
2802 /*IsReinject=*/false);
2803
2804 if (PP.getPPCallbacks())
2805 PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, Name: Ext,
2806 StateLoc, State);
2807}
2808
2809/// Handle '#pragma omp ...' when OpenMP is disabled and '#pragma acc ...' when
2810/// OpenACC is disabled.
2811template <diag::kind IgnoredDiag>
2812void PragmaNoSupportHandler<IgnoredDiag>::HandlePragma(
2813 Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) {
2814 if (!PP.getDiagnostics().isIgnored(DiagID: IgnoredDiag, Loc: FirstTok.getLocation())) {
2815 PP.Diag(Tok: FirstTok, DiagID: IgnoredDiag);
2816 PP.getDiagnostics().setSeverity(Diag: IgnoredDiag, Map: diag::Severity::Ignored,
2817 Loc: SourceLocation());
2818 }
2819 PP.DiscardUntilEndOfDirective();
2820}
2821
2822/// Handle '#pragma omp ...' when OpenMP is enabled, and handle '#pragma acc...'
2823/// when OpenACC is enabled.
2824template <tok::TokenKind StartTok, tok::TokenKind EndTok,
2825 diag::kind UnexpectedDiag>
2826void PragmaSupportHandler<StartTok, EndTok, UnexpectedDiag>::HandlePragma(
2827 Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstTok) {
2828 SmallVector<Token, 16> Pragma;
2829 Token Tok;
2830 Tok.startToken();
2831 Tok.setKind(StartTok);
2832 Tok.setLocation(Introducer.Loc);
2833
2834 while (Tok.isNot(K: tok::eod) && Tok.isNot(K: tok::eof)) {
2835 Pragma.push_back(Elt: Tok);
2836 PP.Lex(Result&: Tok);
2837 if (Tok.is(K: StartTok)) {
2838 PP.Diag(Tok, DiagID: UnexpectedDiag) << 0;
2839 unsigned InnerPragmaCnt = 1;
2840 while (InnerPragmaCnt != 0) {
2841 PP.Lex(Result&: Tok);
2842 if (Tok.is(K: StartTok))
2843 ++InnerPragmaCnt;
2844 else if (Tok.is(K: EndTok))
2845 --InnerPragmaCnt;
2846 }
2847 PP.Lex(Result&: Tok);
2848 }
2849 }
2850 SourceLocation EodLoc = Tok.getLocation();
2851 Tok.startToken();
2852 Tok.setKind(EndTok);
2853 Tok.setLocation(EodLoc);
2854 Pragma.push_back(Elt: Tok);
2855
2856 auto Toks = std::make_unique<Token[]>(num: Pragma.size());
2857 std::copy(first: Pragma.begin(), last: Pragma.end(), result: Toks.get());
2858 PP.EnterTokenStream(Toks: std::move(Toks), NumToks: Pragma.size(),
2859 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
2860}
2861
2862/// Handle '#pragma pointers_to_members'
2863// The grammar for this pragma is as follows:
2864//
2865// <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance'
2866//
2867// #pragma pointers_to_members '(' 'best_case' ')'
2868// #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')'
2869// #pragma pointers_to_members '(' inheritance-model ')'
2870void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP,
2871 PragmaIntroducer Introducer,
2872 Token &Tok) {
2873 SourceLocation PointersToMembersLoc = Tok.getLocation();
2874 PP.Lex(Result&: Tok);
2875 if (Tok.isNot(K: tok::l_paren)) {
2876 PP.Diag(Loc: PointersToMembersLoc, DiagID: diag::warn_pragma_expected_lparen)
2877 << "pointers_to_members";
2878 return;
2879 }
2880 PP.Lex(Result&: Tok);
2881 const IdentifierInfo *Arg = Tok.getIdentifierInfo();
2882 if (!Arg) {
2883 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
2884 << "pointers_to_members";
2885 return;
2886 }
2887 PP.Lex(Result&: Tok);
2888
2889 LangOptions::PragmaMSPointersToMembersKind RepresentationMethod;
2890 if (Arg->isStr(Str: "best_case")) {
2891 RepresentationMethod = LangOptions::PPTMK_BestCase;
2892 } else {
2893 if (Arg->isStr(Str: "full_generality")) {
2894 if (Tok.is(K: tok::comma)) {
2895 PP.Lex(Result&: Tok);
2896
2897 Arg = Tok.getIdentifierInfo();
2898 if (!Arg) {
2899 PP.Diag(Loc: Tok.getLocation(),
2900 DiagID: diag::err_pragma_pointers_to_members_unknown_kind)
2901 << Tok.getKind() << /*OnlyInheritanceModels*/ 0;
2902 return;
2903 }
2904 PP.Lex(Result&: Tok);
2905 } else if (Tok.is(K: tok::r_paren)) {
2906 // #pragma pointers_to_members(full_generality) implicitly specifies
2907 // virtual_inheritance.
2908 Arg = nullptr;
2909 RepresentationMethod = LangOptions::PPTMK_FullGeneralityVirtualInheritance;
2910 } else {
2911 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected_punc)
2912 << "full_generality";
2913 return;
2914 }
2915 }
2916
2917 if (Arg) {
2918 if (Arg->isStr(Str: "single_inheritance")) {
2919 RepresentationMethod =
2920 LangOptions::PPTMK_FullGeneralitySingleInheritance;
2921 } else if (Arg->isStr(Str: "multiple_inheritance")) {
2922 RepresentationMethod =
2923 LangOptions::PPTMK_FullGeneralityMultipleInheritance;
2924 } else if (Arg->isStr(Str: "virtual_inheritance")) {
2925 RepresentationMethod =
2926 LangOptions::PPTMK_FullGeneralityVirtualInheritance;
2927 } else {
2928 PP.Diag(Loc: Tok.getLocation(),
2929 DiagID: diag::err_pragma_pointers_to_members_unknown_kind)
2930 << Arg << /*HasPointerDeclaration*/ 1;
2931 return;
2932 }
2933 }
2934 }
2935
2936 if (Tok.isNot(K: tok::r_paren)) {
2937 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected_rparen_after)
2938 << (Arg ? Arg->getName() : "full_generality");
2939 return;
2940 }
2941
2942 SourceLocation EndLoc = Tok.getLocation();
2943 PP.Lex(Result&: Tok);
2944 if (Tok.isNot(K: tok::eod)) {
2945 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
2946 << "pointers_to_members";
2947 return;
2948 }
2949
2950 Token AnnotTok;
2951 AnnotTok.startToken();
2952 AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members);
2953 AnnotTok.setLocation(PointersToMembersLoc);
2954 AnnotTok.setAnnotationEndLoc(EndLoc);
2955 AnnotTok.setAnnotationValue(
2956 reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod)));
2957 PP.EnterToken(Tok: AnnotTok, /*IsReinject=*/true);
2958}
2959
2960/// Handle '#pragma vtordisp'
2961// The grammar for this pragma is as follows:
2962//
2963// <vtordisp-mode> ::= ('off' | 'on' | '0' | '1' | '2' )
2964//
2965// #pragma vtordisp '(' ['push' ','] vtordisp-mode ')'
2966// #pragma vtordisp '(' 'pop' ')'
2967// #pragma vtordisp '(' ')'
2968void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
2969 PragmaIntroducer Introducer, Token &Tok) {
2970 SourceLocation VtorDispLoc = Tok.getLocation();
2971 PP.Lex(Result&: Tok);
2972 if (Tok.isNot(K: tok::l_paren)) {
2973 PP.Diag(Loc: VtorDispLoc, DiagID: diag::warn_pragma_expected_lparen) << "vtordisp";
2974 return;
2975 }
2976 PP.Lex(Result&: Tok);
2977
2978 Sema::PragmaMsStackAction Action = Sema::PSK_Set;
2979 const IdentifierInfo *II = Tok.getIdentifierInfo();
2980 if (II) {
2981 if (II->isStr(Str: "push")) {
2982 // #pragma vtordisp(push, mode)
2983 PP.Lex(Result&: Tok);
2984 if (Tok.isNot(K: tok::comma)) {
2985 PP.Diag(Loc: VtorDispLoc, DiagID: diag::warn_pragma_expected_punc) << "vtordisp";
2986 return;
2987 }
2988 PP.Lex(Result&: Tok);
2989 Action = Sema::PSK_Push_Set;
2990 // not push, could be on/off
2991 } else if (II->isStr(Str: "pop")) {
2992 // #pragma vtordisp(pop)
2993 PP.Lex(Result&: Tok);
2994 Action = Sema::PSK_Pop;
2995 }
2996 // not push or pop, could be on/off
2997 } else {
2998 if (Tok.is(K: tok::r_paren)) {
2999 // #pragma vtordisp()
3000 Action = Sema::PSK_Reset;
3001 }
3002 }
3003
3004
3005 uint64_t Value = 0;
3006 if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
3007 const IdentifierInfo *II = Tok.getIdentifierInfo();
3008 if (II && II->isStr(Str: "off")) {
3009 PP.Lex(Result&: Tok);
3010 Value = 0;
3011 } else if (II && II->isStr(Str: "on")) {
3012 PP.Lex(Result&: Tok);
3013 Value = 1;
3014 } else if (Tok.is(K: tok::numeric_constant) &&
3015 PP.parseSimpleIntegerLiteral(Tok, Value)) {
3016 if (Value > 2) {
3017 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_integer)
3018 << 0 << 2 << "vtordisp";
3019 return;
3020 }
3021 } else {
3022 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_invalid_action)
3023 << "vtordisp";
3024 return;
3025 }
3026 }
3027
3028 // Finish the pragma: ')' $
3029 if (Tok.isNot(K: tok::r_paren)) {
3030 PP.Diag(Loc: VtorDispLoc, DiagID: diag::warn_pragma_expected_rparen) << "vtordisp";
3031 return;
3032 }
3033 SourceLocation EndLoc = Tok.getLocation();
3034 PP.Lex(Result&: Tok);
3035 if (Tok.isNot(K: tok::eod)) {
3036 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3037 << "vtordisp";
3038 return;
3039 }
3040
3041 // Enter the annotation.
3042 Token AnnotTok;
3043 AnnotTok.startToken();
3044 AnnotTok.setKind(tok::annot_pragma_ms_vtordisp);
3045 AnnotTok.setLocation(VtorDispLoc);
3046 AnnotTok.setAnnotationEndLoc(EndLoc);
3047 AnnotTok.setAnnotationValue(reinterpret_cast<void *>(
3048 static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF))));
3049 PP.EnterToken(Tok: AnnotTok, /*IsReinject=*/false);
3050}
3051
3052/// Handle all MS pragmas. Simply forwards the tokens after inserting
3053/// an annotation token.
3054void PragmaMSPragma::HandlePragma(Preprocessor &PP,
3055 PragmaIntroducer Introducer, Token &Tok) {
3056 Token EoF, AnnotTok;
3057 EoF.startToken();
3058 EoF.setKind(tok::eof);
3059 AnnotTok.startToken();
3060 AnnotTok.setKind(tok::annot_pragma_ms_pragma);
3061 AnnotTok.setLocation(Tok.getLocation());
3062 AnnotTok.setAnnotationEndLoc(Tok.getLocation());
3063 SmallVector<Token, 8> TokenVector;
3064 // Suck up all of the tokens before the eod.
3065 for (; Tok.isNot(K: tok::eod); PP.Lex(Result&: Tok)) {
3066 TokenVector.push_back(Elt: Tok);
3067 AnnotTok.setAnnotationEndLoc(Tok.getLocation());
3068 }
3069 // Add a sentinel EoF token to the end of the list.
3070 TokenVector.push_back(Elt: EoF);
3071 // We must allocate this array with new because EnterTokenStream is going to
3072 // delete it later.
3073 markAsReinjectedForRelexing(Toks: TokenVector);
3074 auto TokenArray = std::make_unique<Token[]>(num: TokenVector.size());
3075 std::copy(first: TokenVector.begin(), last: TokenVector.end(), result: TokenArray.get());
3076 auto Value = new (PP.getPreprocessorAllocator())
3077 std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray),
3078 TokenVector.size());
3079 AnnotTok.setAnnotationValue(Value);
3080 PP.EnterToken(Tok: AnnotTok, /*IsReinject*/ false);
3081}
3082
3083/// Handle the \#pragma float_control extension.
3084///
3085/// The syntax is:
3086/// \code
3087/// #pragma float_control(keyword[, setting] [,push])
3088/// \endcode
3089/// Where 'keyword' and 'setting' are identifiers.
3090// 'keyword' can be: precise, except, push, pop
3091// 'setting' can be: on, off
3092/// The optional arguments 'setting' and 'push' are supported only
3093/// when the keyword is 'precise' or 'except'.
3094void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP,
3095 PragmaIntroducer Introducer,
3096 Token &Tok) {
3097 Sema::PragmaMsStackAction Action = Sema::PSK_Set;
3098 SourceLocation FloatControlLoc = Tok.getLocation();
3099 Token PragmaName = Tok;
3100 if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) {
3101 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_fp_ignored)
3102 << PragmaName.getIdentifierInfo()->getName();
3103 return;
3104 }
3105 PP.Lex(Result&: Tok);
3106 if (Tok.isNot(K: tok::l_paren)) {
3107 PP.Diag(Loc: FloatControlLoc, DiagID: diag::err_expected) << tok::l_paren;
3108 return;
3109 }
3110
3111 // Read the identifier.
3112 PP.Lex(Result&: Tok);
3113 if (Tok.isNot(K: tok::identifier)) {
3114 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3115 return;
3116 }
3117
3118 // Verify that this is one of the float control options.
3119 IdentifierInfo *II = Tok.getIdentifierInfo();
3120 PragmaFloatControlKind Kind =
3121 llvm::StringSwitch<PragmaFloatControlKind>(II->getName())
3122 .Case(S: "precise", Value: PFC_Precise)
3123 .Case(S: "except", Value: PFC_Except)
3124 .Case(S: "push", Value: PFC_Push)
3125 .Case(S: "pop", Value: PFC_Pop)
3126 .Default(Value: PFC_Unknown);
3127 PP.Lex(Result&: Tok); // the identifier
3128 if (Kind == PFC_Unknown) {
3129 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3130 return;
3131 } else if (Kind == PFC_Push || Kind == PFC_Pop) {
3132 if (Tok.isNot(K: tok::r_paren)) {
3133 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3134 return;
3135 }
3136 PP.Lex(Result&: Tok); // Eat the r_paren
3137 Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push;
3138 } else {
3139 if (Tok.is(K: tok::r_paren))
3140 // Selecting Precise or Except
3141 PP.Lex(Result&: Tok); // the r_paren
3142 else if (Tok.isNot(K: tok::comma)) {
3143 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3144 return;
3145 } else {
3146 PP.Lex(Result&: Tok); // ,
3147 if (!Tok.isAnyIdentifier()) {
3148 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3149 return;
3150 }
3151 StringRef PushOnOff = Tok.getIdentifierInfo()->getName();
3152 if (PushOnOff == "on")
3153 // Kind is set correctly
3154 ;
3155 else if (PushOnOff == "off") {
3156 if (Kind == PFC_Precise)
3157 Kind = PFC_NoPrecise;
3158 if (Kind == PFC_Except)
3159 Kind = PFC_NoExcept;
3160 } else if (PushOnOff == "push") {
3161 Action = Sema::PSK_Push_Set;
3162 } else {
3163 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3164 return;
3165 }
3166 PP.Lex(Result&: Tok); // the identifier
3167 if (Tok.is(K: tok::comma)) {
3168 PP.Lex(Result&: Tok); // ,
3169 if (!Tok.isAnyIdentifier()) {
3170 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3171 return;
3172 }
3173 StringRef ExpectedPush = Tok.getIdentifierInfo()->getName();
3174 if (ExpectedPush == "push") {
3175 Action = Sema::PSK_Push_Set;
3176 } else {
3177 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3178 return;
3179 }
3180 PP.Lex(Result&: Tok); // the push identifier
3181 }
3182 if (Tok.isNot(K: tok::r_paren)) {
3183 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_float_control_malformed);
3184 return;
3185 }
3186 PP.Lex(Result&: Tok); // the r_paren
3187 }
3188 }
3189 SourceLocation EndLoc = Tok.getLocation();
3190 if (Tok.isNot(K: tok::eod)) {
3191 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3192 << "float_control";
3193 return;
3194 }
3195
3196 // Note: there is no accomodation for PP callback for this pragma.
3197
3198 // Enter the annotation.
3199 auto TokenArray = std::make_unique<Token[]>(num: 1);
3200 TokenArray[0].startToken();
3201 TokenArray[0].setKind(tok::annot_pragma_float_control);
3202 TokenArray[0].setLocation(FloatControlLoc);
3203 TokenArray[0].setAnnotationEndLoc(EndLoc);
3204 // Create an encoding of Action and Value by shifting the Action into
3205 // the high 16 bits then union with the Kind.
3206 TokenArray[0].setAnnotationValue(reinterpret_cast<void *>(
3207 static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF))));
3208 PP.EnterTokenStream(Toks: std::move(TokenArray), NumToks: 1,
3209 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
3210}
3211
3212/// Handle the Microsoft \#pragma detect_mismatch extension.
3213///
3214/// The syntax is:
3215/// \code
3216/// #pragma detect_mismatch("name", "value")
3217/// \endcode
3218/// Where 'name' and 'value' are quoted strings. The values are embedded in
3219/// the object file and passed along to the linker. If the linker detects a
3220/// mismatch in the object file's values for the given name, a LNK2038 error
3221/// is emitted. See MSDN for more details.
3222void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP,
3223 PragmaIntroducer Introducer,
3224 Token &Tok) {
3225 SourceLocation DetectMismatchLoc = Tok.getLocation();
3226 PP.Lex(Result&: Tok);
3227 if (Tok.isNot(K: tok::l_paren)) {
3228 PP.Diag(Loc: DetectMismatchLoc, DiagID: diag::err_expected) << tok::l_paren;
3229 return;
3230 }
3231
3232 // Read the name to embed, which must be a string literal.
3233 std::string NameString;
3234 if (!PP.LexStringLiteral(Result&: Tok, String&: NameString,
3235 DiagnosticTag: "pragma detect_mismatch",
3236 /*AllowMacroExpansion=*/true))
3237 return;
3238
3239 // Read the comma followed by a second string literal.
3240 std::string ValueString;
3241 if (Tok.isNot(K: tok::comma)) {
3242 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_detect_mismatch_malformed);
3243 return;
3244 }
3245
3246 if (!PP.LexStringLiteral(Result&: Tok, String&: ValueString, DiagnosticTag: "pragma detect_mismatch",
3247 /*AllowMacroExpansion=*/true))
3248 return;
3249
3250 if (Tok.isNot(K: tok::r_paren)) {
3251 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::r_paren;
3252 return;
3253 }
3254 PP.Lex(Result&: Tok); // Eat the r_paren.
3255
3256 if (Tok.isNot(K: tok::eod)) {
3257 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_detect_mismatch_malformed);
3258 return;
3259 }
3260
3261 // If the pragma is lexically sound, notify any interested PPCallbacks.
3262 if (PP.getPPCallbacks())
3263 PP.getPPCallbacks()->PragmaDetectMismatch(Loc: DetectMismatchLoc, Name: NameString,
3264 Value: ValueString);
3265
3266 Actions.ActOnPragmaDetectMismatch(Loc: DetectMismatchLoc, Name: NameString, Value: ValueString);
3267}
3268
3269/// Handle the microsoft \#pragma comment extension.
3270///
3271/// The syntax is:
3272/// \code
3273/// #pragma comment(linker, "foo")
3274/// \endcode
3275/// 'linker' is one of six identifiers: compiler, copyright, exestr, lib,
3276/// linker, user.
3277///
3278/// "foo" is a string, which is fully macro expanded, and permits string
3279/// concatenation, embedded escape characters etc. See MSDN for more details.
3280void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
3281 PragmaIntroducer Introducer,
3282 Token &Tok) {
3283 SourceLocation CommentLoc = Tok.getLocation();
3284 PP.Lex(Result&: Tok);
3285 if (Tok.isNot(K: tok::l_paren)) {
3286 PP.Diag(Loc: CommentLoc, DiagID: diag::err_pragma_comment_malformed);
3287 return;
3288 }
3289
3290 // Read the identifier.
3291 PP.Lex(Result&: Tok);
3292 if (Tok.isNot(K: tok::identifier)) {
3293 PP.Diag(Loc: CommentLoc, DiagID: diag::err_pragma_comment_malformed);
3294 return;
3295 }
3296
3297 // Verify that this is one of the 6 explicitly listed options.
3298 IdentifierInfo *II = Tok.getIdentifierInfo();
3299 PragmaMSCommentKind Kind =
3300 llvm::StringSwitch<PragmaMSCommentKind>(II->getName())
3301 .Case(S: "linker", Value: PCK_Linker)
3302 .Case(S: "lib", Value: PCK_Lib)
3303 .Case(S: "compiler", Value: PCK_Compiler)
3304 .Case(S: "exestr", Value: PCK_ExeStr)
3305 .Case(S: "user", Value: PCK_User)
3306 .Case(S: "copyright", Value: PCK_Copyright)
3307 .Default(Value: PCK_Unknown);
3308 if (Kind == PCK_Unknown) {
3309 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_comment_unknown_kind);
3310 return;
3311 }
3312
3313 if (PP.getTargetInfo().getTriple().isOSAIX() && Kind != PCK_Copyright) {
3314 // Currently, pragma comment kinds aside from "copyright" are not fully
3315 // implemented by Clang for AIX targets.
3316 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_comment_ignored)
3317 << II->getName();
3318 return;
3319 }
3320
3321 if (PP.getTargetInfo().getTriple().isOSBinFormatELF() && Kind != PCK_Lib) {
3322 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_comment_ignored)
3323 << II->getName();
3324 return;
3325 }
3326
3327 // Handle pragma comment copyright kind.
3328 if (Kind == PCK_Copyright) {
3329 if (SeenCopyrightInTU) {
3330 // pragma comment copyright can each appear only once in a TU.
3331 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_comment_once)
3332 << II->getName();
3333 return;
3334 }
3335 SeenCopyrightInTU = true;
3336 }
3337
3338 // Read the optional string if present.
3339 PP.Lex(Result&: Tok);
3340 std::string ArgumentString;
3341 if (Tok.is(K: tok::comma) && !PP.LexStringLiteral(Result&: Tok, String&: ArgumentString,
3342 DiagnosticTag: "pragma comment",
3343 /*AllowMacroExpansion=*/true))
3344 return;
3345
3346 // FIXME: warn that 'exestr' is deprecated.
3347 // FIXME: If the kind is "compiler" warn if the string is present (it is
3348 // ignored).
3349 // The MSDN docs say that "lib" and "linker" require a string and have a short
3350 // list of linker options they support, but in practice MSVC doesn't
3351 // issue a diagnostic. Therefore neither does clang.
3352
3353 if (Tok.isNot(K: tok::r_paren)) {
3354 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_comment_malformed);
3355 return;
3356 }
3357 PP.Lex(Result&: Tok); // eat the r_paren.
3358
3359 if (Tok.isNot(K: tok::eod)) {
3360 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_comment_malformed);
3361 return;
3362 }
3363
3364 // Skip further processing for well-formed copyright with an empty string.
3365 if (Kind == PCK_Copyright && ArgumentString.empty())
3366 return;
3367
3368 // If the pragma is lexically sound, notify any interested PPCallbacks.
3369 if (PP.getPPCallbacks())
3370 PP.getPPCallbacks()->PragmaComment(Loc: CommentLoc, Kind: II, Str: ArgumentString);
3371
3372 Actions.ActOnPragmaMSComment(CommentLoc, Kind, Arg: ArgumentString);
3373}
3374
3375// #pragma clang optimize off
3376// #pragma clang optimize on
3377void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
3378 PragmaIntroducer Introducer,
3379 Token &FirstToken) {
3380 Token Tok;
3381 PP.Lex(Result&: Tok);
3382 if (Tok.is(K: tok::eod)) {
3383 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_missing_argument)
3384 << "clang optimize" << /*Expected=*/true << "'on' or 'off'";
3385 return;
3386 }
3387 if (Tok.isNot(K: tok::identifier)) {
3388 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_optimize_invalid_argument)
3389 << PP.getSpelling(Tok);
3390 return;
3391 }
3392 const IdentifierInfo *II = Tok.getIdentifierInfo();
3393 // The only accepted values are 'on' or 'off'.
3394 bool IsOn = false;
3395 if (II->isStr(Str: "on")) {
3396 IsOn = true;
3397 } else if (!II->isStr(Str: "off")) {
3398 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_optimize_invalid_argument)
3399 << PP.getSpelling(Tok);
3400 return;
3401 }
3402 PP.Lex(Result&: Tok);
3403
3404 if (Tok.isNot(K: tok::eod)) {
3405 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_optimize_extra_argument)
3406 << PP.getSpelling(Tok);
3407 return;
3408 }
3409
3410 Actions.ActOnPragmaOptimize(On: IsOn, PragmaLoc: FirstToken.getLocation());
3411}
3412
3413namespace {
3414/// Used as the annotation value for tok::annot_pragma_fp.
3415struct TokFPAnnotValue {
3416 enum FlagValues { On, Off, Fast };
3417
3418 std::optional<LangOptions::FPModeKind> ContractValue;
3419 std::optional<LangOptions::FPModeKind> ReassociateValue;
3420 std::optional<LangOptions::FPModeKind> ReciprocalValue;
3421 std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
3422 std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
3423};
3424} // end anonymous namespace
3425
3426void PragmaFPHandler::HandlePragma(Preprocessor &PP,
3427 PragmaIntroducer Introducer, Token &Tok) {
3428 // fp
3429 Token PragmaName = Tok;
3430 SmallVector<Token, 1> TokenList;
3431
3432 PP.Lex(Result&: Tok);
3433 if (Tok.isNot(K: tok::identifier)) {
3434 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_option)
3435 << /*MissingOption=*/true << "";
3436 return;
3437 }
3438
3439 auto *AnnotValue = new (PP.getPreprocessorAllocator()) TokFPAnnotValue;
3440 while (Tok.is(K: tok::identifier)) {
3441 IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
3442
3443 auto FlagKind =
3444 llvm::StringSwitch<std::optional<PragmaFPKind>>(OptionInfo->getName())
3445 .Case(S: "contract", Value: PFK_Contract)
3446 .Case(S: "reassociate", Value: PFK_Reassociate)
3447 .Case(S: "exceptions", Value: PFK_Exceptions)
3448 .Case(S: "eval_method", Value: PFK_EvalMethod)
3449 .Case(S: "reciprocal", Value: PFK_Reciprocal)
3450 .Default(Value: std::nullopt);
3451 if (!FlagKind) {
3452 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_option)
3453 << /*MissingOption=*/false << OptionInfo;
3454 return;
3455 }
3456 PP.Lex(Result&: Tok);
3457
3458 // Read '('
3459 if (Tok.isNot(K: tok::l_paren)) {
3460 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::l_paren;
3461 return;
3462 }
3463 PP.Lex(Result&: Tok);
3464 bool isEvalMethodDouble =
3465 Tok.is(K: tok::kw_double) && FlagKind == PFK_EvalMethod;
3466
3467 // Don't diagnose if we have an eval_metod pragma with "double" kind.
3468 if (Tok.isNot(K: tok::identifier) && !isEvalMethodDouble) {
3469 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_argument)
3470 << PP.getSpelling(Tok) << OptionInfo->getName()
3471 << static_cast<int>(*FlagKind);
3472 return;
3473 }
3474 const IdentifierInfo *II = Tok.getIdentifierInfo();
3475
3476 if (FlagKind == PFK_Contract) {
3477 AnnotValue->ContractValue =
3478 llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
3479 II->getName())
3480 .Case(S: "on", Value: LangOptions::FPModeKind::FPM_On)
3481 .Case(S: "off", Value: LangOptions::FPModeKind::FPM_Off)
3482 .Case(S: "fast", Value: LangOptions::FPModeKind::FPM_Fast)
3483 .Default(Value: std::nullopt);
3484 if (!AnnotValue->ContractValue) {
3485 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_argument)
3486 << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
3487 return;
3488 }
3489 } else if (FlagKind == PFK_Reassociate || FlagKind == PFK_Reciprocal) {
3490 auto &Value = FlagKind == PFK_Reassociate ? AnnotValue->ReassociateValue
3491 : AnnotValue->ReciprocalValue;
3492 Value = llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
3493 II->getName())
3494 .Case(S: "on", Value: LangOptions::FPModeKind::FPM_On)
3495 .Case(S: "off", Value: LangOptions::FPModeKind::FPM_Off)
3496 .Default(Value: std::nullopt);
3497 if (!Value) {
3498 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_argument)
3499 << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
3500 return;
3501 }
3502 } else if (FlagKind == PFK_Exceptions) {
3503 AnnotValue->ExceptionsValue =
3504 llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>(
3505 II->getName())
3506 .Case(S: "ignore", Value: LangOptions::FPE_Ignore)
3507 .Case(S: "maytrap", Value: LangOptions::FPE_MayTrap)
3508 .Case(S: "strict", Value: LangOptions::FPE_Strict)
3509 .Default(Value: std::nullopt);
3510 if (!AnnotValue->ExceptionsValue) {
3511 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_argument)
3512 << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
3513 return;
3514 }
3515 } else if (FlagKind == PFK_EvalMethod) {
3516 AnnotValue->EvalMethodValue =
3517 llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>(
3518 II->getName())
3519 .Case(S: "source", Value: LangOptions::FPEvalMethodKind::FEM_Source)
3520 .Case(S: "double", Value: LangOptions::FPEvalMethodKind::FEM_Double)
3521 .Case(S: "extended", Value: LangOptions::FPEvalMethodKind::FEM_Extended)
3522 .Default(Value: std::nullopt);
3523 if (!AnnotValue->EvalMethodValue) {
3524 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_fp_invalid_argument)
3525 << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
3526 return;
3527 }
3528 }
3529 PP.Lex(Result&: Tok);
3530
3531 // Read ')'
3532 if (Tok.isNot(K: tok::r_paren)) {
3533 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::r_paren;
3534 return;
3535 }
3536 PP.Lex(Result&: Tok);
3537 }
3538
3539 if (Tok.isNot(K: tok::eod)) {
3540 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3541 << "clang fp";
3542 return;
3543 }
3544
3545 Token FPTok;
3546 FPTok.startToken();
3547 FPTok.setKind(tok::annot_pragma_fp);
3548 FPTok.setLocation(PragmaName.getLocation());
3549 FPTok.setAnnotationEndLoc(PragmaName.getLocation());
3550 FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue));
3551 TokenList.push_back(Elt: FPTok);
3552
3553 auto TokenArray = std::make_unique<Token[]>(num: TokenList.size());
3554 std::copy(first: TokenList.begin(), last: TokenList.end(), result: TokenArray.get());
3555
3556 PP.EnterTokenStream(Toks: std::move(TokenArray), NumToks: TokenList.size(),
3557 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
3558}
3559
3560void PragmaSTDC_FENV_ROUNDHandler::HandlePragma(Preprocessor &PP,
3561 PragmaIntroducer Introducer,
3562 Token &Tok) {
3563 Token PragmaName = Tok;
3564 if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) {
3565 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_fp_ignored)
3566 << PragmaName.getIdentifierInfo()->getName();
3567 return;
3568 }
3569
3570 PP.Lex(Result&: Tok);
3571 if (Tok.isNot(K: tok::identifier)) {
3572 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_expected_identifier)
3573 << PragmaName.getIdentifierInfo()->getName();
3574 return;
3575 }
3576 IdentifierInfo *II = Tok.getIdentifierInfo();
3577
3578 auto RM =
3579 llvm::StringSwitch<llvm::RoundingMode>(II->getName())
3580 .Case(S: "FE_TOWARDZERO", Value: llvm::RoundingMode::TowardZero)
3581 .Case(S: "FE_TONEAREST", Value: llvm::RoundingMode::NearestTiesToEven)
3582 .Case(S: "FE_UPWARD", Value: llvm::RoundingMode::TowardPositive)
3583 .Case(S: "FE_DOWNWARD", Value: llvm::RoundingMode::TowardNegative)
3584 .Case(S: "FE_TONEARESTFROMZERO", Value: llvm::RoundingMode::NearestTiesToAway)
3585 .Case(S: "FE_DYNAMIC", Value: llvm::RoundingMode::Dynamic)
3586 .Default(Value: llvm::RoundingMode::Invalid);
3587 if (RM == llvm::RoundingMode::Invalid) {
3588 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_stdc_unknown_rounding_mode);
3589 return;
3590 }
3591 PP.Lex(Result&: Tok);
3592
3593 if (Tok.isNot(K: tok::eod)) {
3594 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3595 << "STDC FENV_ROUND";
3596 return;
3597 }
3598
3599 // Until the pragma is fully implemented, issue a warning.
3600 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_stdc_fenv_round_not_supported);
3601
3602 MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(Num: 1),
3603 1);
3604 Toks[0].startToken();
3605 Toks[0].setKind(tok::annot_pragma_fenv_round);
3606 Toks[0].setLocation(Tok.getLocation());
3607 Toks[0].setAnnotationEndLoc(Tok.getLocation());
3608 Toks[0].setAnnotationValue(
3609 reinterpret_cast<void *>(static_cast<uintptr_t>(RM)));
3610 PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
3611 /*IsReinject=*/false);
3612}
3613
3614void Parser::HandlePragmaFP() {
3615 assert(Tok.is(tok::annot_pragma_fp));
3616 auto *AnnotValue =
3617 reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue());
3618
3619 if (AnnotValue->ReassociateValue)
3620 Actions.ActOnPragmaFPValueChangingOption(
3621 Loc: Tok.getLocation(), Kind: PFK_Reassociate,
3622 IsEnabled: *AnnotValue->ReassociateValue == LangOptions::FPModeKind::FPM_On);
3623
3624 if (AnnotValue->ReciprocalValue)
3625 Actions.ActOnPragmaFPValueChangingOption(
3626 Loc: Tok.getLocation(), Kind: PFK_Reciprocal,
3627 IsEnabled: *AnnotValue->ReciprocalValue == LangOptions::FPModeKind::FPM_On);
3628
3629 if (AnnotValue->ContractValue)
3630 Actions.ActOnPragmaFPContract(Loc: Tok.getLocation(),
3631 FPC: *AnnotValue->ContractValue);
3632 if (AnnotValue->ExceptionsValue)
3633 Actions.ActOnPragmaFPExceptions(Loc: Tok.getLocation(),
3634 *AnnotValue->ExceptionsValue);
3635 if (AnnotValue->EvalMethodValue)
3636 Actions.ActOnPragmaFPEvalMethod(Loc: Tok.getLocation(),
3637 Value: *AnnotValue->EvalMethodValue);
3638 ConsumeAnnotationToken();
3639}
3640
3641/// Parses loop or unroll pragma hint value and fills in Info.
3642static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
3643 Token Option, bool ValueInParens,
3644 PragmaLoopHintInfo &Info) {
3645 SmallVector<Token, 1> ValueList;
3646 int OpenParens = ValueInParens ? 1 : 0;
3647 // Read constant expression.
3648 while (Tok.isNot(K: tok::eod)) {
3649 if (Tok.is(K: tok::l_paren))
3650 OpenParens++;
3651 else if (Tok.is(K: tok::r_paren)) {
3652 OpenParens--;
3653 if (OpenParens == 0 && ValueInParens)
3654 break;
3655 }
3656
3657 ValueList.push_back(Elt: Tok);
3658 PP.Lex(Result&: Tok);
3659 }
3660
3661 if (ValueInParens) {
3662 // Read ')'
3663 if (Tok.isNot(K: tok::r_paren)) {
3664 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::r_paren;
3665 return true;
3666 }
3667 PP.Lex(Result&: Tok);
3668 }
3669
3670 Token EOFTok;
3671 EOFTok.startToken();
3672 EOFTok.setKind(tok::eof);
3673 EOFTok.setLocation(Tok.getLocation());
3674 ValueList.push_back(Elt: EOFTok); // Terminates expression for parsing.
3675
3676 markAsReinjectedForRelexing(Toks: ValueList);
3677 Info.Toks = llvm::ArrayRef(ValueList).copy(A&: PP.getPreprocessorAllocator());
3678
3679 Info.PragmaName = PragmaName;
3680 Info.Option = Option;
3681 return false;
3682}
3683
3684/// Handle the \#pragma clang loop directive.
3685/// #pragma clang 'loop' loop-hints
3686///
3687/// loop-hints:
3688/// loop-hint loop-hints[opt]
3689///
3690/// loop-hint:
3691/// 'vectorize' '(' loop-hint-keyword ')'
3692/// 'interleave' '(' loop-hint-keyword ')'
3693/// 'unroll' '(' unroll-hint-keyword ')'
3694/// 'vectorize_predicate' '(' loop-hint-keyword ')'
3695/// 'vectorize_width' '(' loop-hint-value ')'
3696/// 'interleave_count' '(' loop-hint-value ')'
3697/// 'unroll_count' '(' loop-hint-value ')'
3698/// 'pipeline' '(' disable ')'
3699/// 'pipeline_initiation_interval' '(' loop-hint-value ')'
3700///
3701/// loop-hint-keyword:
3702/// 'enable'
3703/// 'disable'
3704/// 'assume_safety'
3705///
3706/// unroll-hint-keyword:
3707/// 'enable'
3708/// 'disable'
3709/// 'full'
3710///
3711/// loop-hint-value:
3712/// constant-expression
3713///
3714/// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to
3715/// try vectorizing the instructions of the loop it precedes. Specifying
3716/// interleave(enable) or interleave_count(_value_) instructs llvm to try
3717/// interleaving multiple iterations of the loop it precedes. The width of the
3718/// vector instructions is specified by vectorize_width() and the number of
3719/// interleaved loop iterations is specified by interleave_count(). Specifying a
3720/// value of 1 effectively disables vectorization/interleaving, even if it is
3721/// possible and profitable, and 0 is invalid. The loop vectorizer currently
3722/// only works on inner loops.
3723///
3724/// The unroll and unroll_count directives control the concatenation
3725/// unroller. Specifying unroll(enable) instructs llvm to unroll the loop
3726/// completely if the trip count is known at compile time and unroll partially
3727/// if the trip count is not known. Specifying unroll(full) is similar to
3728/// unroll(enable) but will unroll the loop only if the trip count is known at
3729/// compile time. Specifying unroll(disable) disables unrolling for the
3730/// loop. Specifying unroll_count(_value_) instructs llvm to try to unroll the
3731/// loop the number of times indicated by the value.
3732void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
3733 PragmaIntroducer Introducer,
3734 Token &Tok) {
3735 // Incoming token is "loop" from "#pragma clang loop".
3736 Token PragmaName = Tok;
3737 SmallVector<Token, 1> TokenList;
3738
3739 // Lex the optimization option and verify it is an identifier.
3740 PP.Lex(Result&: Tok);
3741 if (Tok.isNot(K: tok::identifier)) {
3742 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_loop_invalid_option)
3743 << /*MissingOption=*/true << "";
3744 return;
3745 }
3746
3747 while (Tok.is(K: tok::identifier)) {
3748 Token Option = Tok;
3749 IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
3750
3751 bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
3752 .Case(S: "vectorize", Value: true)
3753 .Case(S: "interleave", Value: true)
3754 .Case(S: "unroll", Value: true)
3755 .Case(S: "distribute", Value: true)
3756 .Case(S: "vectorize_predicate", Value: true)
3757 .Case(S: "vectorize_width", Value: true)
3758 .Case(S: "interleave_count", Value: true)
3759 .Case(S: "unroll_count", Value: true)
3760 .Case(S: "pipeline", Value: true)
3761 .Case(S: "pipeline_initiation_interval", Value: true)
3762 .Case(S: "licm", Value: true)
3763 .Default(Value: false);
3764 if (!OptionValid) {
3765 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_loop_invalid_option)
3766 << /*MissingOption=*/false << OptionInfo;
3767 return;
3768 }
3769 PP.Lex(Result&: Tok);
3770
3771 // Read '('
3772 if (Tok.isNot(K: tok::l_paren)) {
3773 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::l_paren;
3774 return;
3775 }
3776 PP.Lex(Result&: Tok);
3777
3778 auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
3779 if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true,
3780 Info&: *Info))
3781 return;
3782
3783 // Generate the loop hint token.
3784 Token LoopHintTok;
3785 LoopHintTok.startToken();
3786 LoopHintTok.setKind(tok::annot_pragma_loop_hint);
3787 LoopHintTok.setLocation(Introducer.Loc);
3788 LoopHintTok.setAnnotationEndLoc(PragmaName.getLocation());
3789 LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
3790 TokenList.push_back(Elt: LoopHintTok);
3791 }
3792
3793 if (Tok.isNot(K: tok::eod)) {
3794 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3795 << "clang loop";
3796 return;
3797 }
3798
3799 auto TokenArray = std::make_unique<Token[]>(num: TokenList.size());
3800 std::copy(first: TokenList.begin(), last: TokenList.end(), result: TokenArray.get());
3801
3802 PP.EnterTokenStream(Toks: std::move(TokenArray), NumToks: TokenList.size(),
3803 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
3804}
3805
3806/// Handle the loop unroll optimization pragmas.
3807/// #pragma unroll
3808/// #pragma unroll unroll-hint-value
3809/// #pragma unroll '(' unroll-hint-value ')'
3810/// #pragma nounroll
3811/// #pragma unroll_and_jam
3812/// #pragma unroll_and_jam unroll-hint-value
3813/// #pragma unroll_and_jam '(' unroll-hint-value ')'
3814/// #pragma nounroll_and_jam
3815///
3816/// unroll-hint-value:
3817/// constant-expression
3818///
3819/// Loop unrolling hints can be specified with '#pragma unroll' or
3820/// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally
3821/// contained in parentheses. With no argument the directive instructs llvm to
3822/// try to unroll the loop completely. A positive integer argument can be
3823/// specified to indicate the number of times the loop should be unrolled. To
3824/// maximize compatibility with other compilers the unroll count argument can be
3825/// specified with or without parentheses. Specifying, '#pragma nounroll'
3826/// disables unrolling of the loop.
3827void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
3828 PragmaIntroducer Introducer,
3829 Token &Tok) {
3830 // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for
3831 // "#pragma nounroll".
3832 Token PragmaName = Tok;
3833 PP.Lex(Result&: Tok);
3834 auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
3835 if (Tok.is(K: tok::eod)) {
3836 // nounroll or unroll pragma without an argument.
3837 Info->PragmaName = PragmaName;
3838 Info->Option.startToken();
3839 } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll" ||
3840 PragmaName.getIdentifierInfo()->getName() == "nounroll_and_jam") {
3841 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3842 << PragmaName.getIdentifierInfo()->getName();
3843 return;
3844 } else {
3845 // Unroll pragma with an argument: "#pragma unroll N" or
3846 // "#pragma unroll(N)".
3847 // Read '(' if it exists.
3848 bool ValueInParens = Tok.is(K: tok::l_paren);
3849 if (ValueInParens)
3850 PP.Lex(Result&: Tok);
3851
3852 Token Option;
3853 Option.startToken();
3854 if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, Info&: *Info))
3855 return;
3856
3857 // In CUDA, the argument to '#pragma unroll' should not be contained in
3858 // parentheses.
3859 if (PP.getLangOpts().CUDA && ValueInParens)
3860 PP.Diag(Loc: Info->Toks[0].getLocation(),
3861 DiagID: diag::warn_pragma_unroll_cuda_value_in_parens);
3862
3863 if (Tok.isNot(K: tok::eod)) {
3864 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
3865 << "unroll";
3866 return;
3867 }
3868 }
3869
3870 // Generate the hint token.
3871 auto TokenArray = std::make_unique<Token[]>(num: 1);
3872 TokenArray[0].startToken();
3873 TokenArray[0].setKind(tok::annot_pragma_loop_hint);
3874 TokenArray[0].setLocation(Introducer.Loc);
3875 TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation());
3876 TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
3877 PP.EnterTokenStream(Toks: std::move(TokenArray), NumToks: 1,
3878 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
3879}
3880
3881bool Parser::HandlePragmaMSFunction(StringRef PragmaName,
3882 SourceLocation PragmaLocation) {
3883 Token FirstTok = Tok;
3884
3885 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
3886 DiagMsg: PragmaName))
3887 return false;
3888
3889 bool SuggestIntrinH = !PP.isMacroDefined(Id: "__INTRIN_H");
3890
3891 llvm::SmallVector<StringRef> NoBuiltins;
3892 while (Tok.is(K: tok::identifier)) {
3893 IdentifierInfo *II = Tok.getIdentifierInfo();
3894 if (!II->getBuiltinID())
3895 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_intrinsic_builtin)
3896 << II << SuggestIntrinH;
3897 else
3898 NoBuiltins.emplace_back(Args: II->getName());
3899
3900 PP.Lex(Result&: Tok);
3901 if (Tok.isNot(K: tok::comma))
3902 break;
3903 PP.Lex(Result&: Tok); // ,
3904 }
3905
3906 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
3907 DiagMsg: PragmaName) ||
3908 ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
3909 DiagMsg: PragmaName))
3910 return false;
3911
3912 Actions.ActOnPragmaMSFunction(Loc: FirstTok.getLocation(), NoBuiltins);
3913 return true;
3914}
3915
3916bool Parser::HandlePragmaMSOptimize(StringRef PragmaName,
3917 SourceLocation PragmaLocation) {
3918 Token FirstTok = Tok;
3919 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
3920 DiagMsg: PragmaName))
3921 return false;
3922
3923 if (Tok.isNot(K: tok::string_literal)) {
3924 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_string) << PragmaName;
3925 return false;
3926 }
3927 ExprResult StringResult = ParseStringLiteralExpression();
3928 if (StringResult.isInvalid())
3929 return false; // Already diagnosed.
3930 StringLiteral *OptimizationList = cast<StringLiteral>(Val: StringResult.get());
3931 if (OptimizationList->getCharByteWidth() != 1) {
3932 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_expected_non_wide_string)
3933 << PragmaName;
3934 return false;
3935 }
3936
3937 if (ExpectAndConsume(ExpectedTok: tok::comma, Diag: diag::warn_pragma_expected_comma,
3938 DiagMsg: PragmaName))
3939 return false;
3940
3941 if (Tok.is(K: tok::eof) || Tok.is(K: tok::r_paren)) {
3942 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_missing_argument)
3943 << PragmaName << /*Expected=*/true << "'on' or 'off'";
3944 return false;
3945 }
3946 IdentifierInfo *II = Tok.getIdentifierInfo();
3947 if (!II || (!II->isStr(Str: "on") && !II->isStr(Str: "off"))) {
3948 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_invalid_argument)
3949 << PP.getSpelling(Tok) << PragmaName << /*Expected=*/true
3950 << "'on' or 'off'";
3951 return false;
3952 }
3953 bool IsOn = II->isStr(Str: "on");
3954 PP.Lex(Result&: Tok);
3955
3956 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
3957 DiagMsg: PragmaName))
3958 return false;
3959
3960 // TODO: Add support for "sgty"
3961 if (!OptimizationList->getString().empty()) {
3962 PP.Diag(Loc: PragmaLocation, DiagID: diag::warn_pragma_invalid_argument)
3963 << OptimizationList->getString() << PragmaName << /*Expected=*/true
3964 << "\"\"";
3965 return false;
3966 }
3967
3968 if (ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
3969 DiagMsg: PragmaName))
3970 return false;
3971
3972 Actions.ActOnPragmaMSOptimize(Loc: FirstTok.getLocation(), IsOn);
3973 return true;
3974}
3975
3976/// Handle the Microsoft \#pragma intrinsic extension.
3977///
3978/// The syntax is:
3979/// \code
3980/// #pragma intrinsic(memset)
3981/// #pragma intrinsic(strlen, memcpy)
3982/// \endcode
3983///
3984/// Pragma intrisic tells the compiler to use a builtin version of the
3985/// function. Clang does it anyway, so the pragma doesn't really do anything.
3986/// Anyway, we emit a warning if the function specified in \#pragma intrinsic
3987/// isn't an intrinsic in clang and suggest to include intrin.h, as well as
3988/// declare the builtin if it has not been declared.
3989bool Parser::HandlePragmaMSIntrinsic(StringRef PragmaName,
3990 SourceLocation PragmaLocation) {
3991 if (ExpectAndConsume(ExpectedTok: tok::l_paren, Diag: diag::warn_pragma_expected_lparen,
3992 DiagMsg: PragmaName))
3993 return false;
3994
3995 bool SuggestIntrinH = !PP.isMacroDefined(Id: "__INTRIN_H");
3996
3997 while (Tok.is(K: tok::identifier)) {
3998 IdentifierInfo *II = Tok.getIdentifierInfo();
3999 if (!II->getBuiltinID())
4000 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_intrinsic_builtin)
4001 << II << SuggestIntrinH;
4002 // If the builtin hasn't already been declared, declare it now.
4003 DeclarationNameInfo NameInfo(II, Tok.getLocation());
4004 LookupResult Previous(Actions, NameInfo, Sema::LookupOrdinaryName,
4005 RedeclarationKind::NotForRedeclaration);
4006 Actions.LookupName(R&: Previous, S: Actions.getCurScope(),
4007 /*CreateBuiltins*/ AllowBuiltinCreation: false);
4008 if (Previous.empty())
4009 Actions.LazilyCreateBuiltin(II, ID: II->getBuiltinID(), S: Actions.getCurScope(),
4010 /*ForRedeclaration*/ true, Loc: Tok.getLocation());
4011 PP.Lex(Result&: Tok);
4012 if (Tok.isNot(K: tok::comma))
4013 break;
4014 PP.Lex(Result&: Tok);
4015 }
4016 if (ExpectAndConsume(ExpectedTok: tok::r_paren, Diag: diag::warn_pragma_expected_rparen,
4017 DiagMsg: PragmaName))
4018 return false;
4019
4020 if (ExpectAndConsume(ExpectedTok: tok::eof, Diag: diag::warn_pragma_extra_tokens_at_eol,
4021 DiagMsg: PragmaName))
4022 return false;
4023 return true;
4024}
4025
4026void PragmaForceCUDAHostDeviceHandler::HandlePragma(
4027 Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) {
4028 Token FirstTok = Tok;
4029
4030 PP.Lex(Result&: Tok);
4031 IdentifierInfo *Info = Tok.getIdentifierInfo();
4032 if (!Info || (!Info->isStr(Str: "begin") && !Info->isStr(Str: "end"))) {
4033 PP.Diag(Loc: FirstTok.getLocation(),
4034 DiagID: diag::warn_pragma_force_cuda_host_device_bad_arg);
4035 return;
4036 }
4037
4038 if (Info->isStr(Str: "begin"))
4039 Actions.CUDA().PushForceHostDevice();
4040 else if (!Actions.CUDA().PopForceHostDevice())
4041 PP.Diag(Loc: FirstTok.getLocation(),
4042 DiagID: diag::err_pragma_cannot_end_force_cuda_host_device);
4043
4044 PP.Lex(Result&: Tok);
4045 if (!Tok.is(K: tok::eod))
4046 PP.Diag(Loc: FirstTok.getLocation(),
4047 DiagID: diag::warn_pragma_force_cuda_host_device_bad_arg);
4048}
4049
4050/// Handle the #pragma clang attribute directive.
4051///
4052/// The syntax is:
4053/// \code
4054/// #pragma clang attribute push (attribute, subject-set)
4055/// #pragma clang attribute push
4056/// #pragma clang attribute (attribute, subject-set)
4057/// #pragma clang attribute pop
4058/// \endcode
4059///
4060/// There are also 'namespace' variants of push and pop directives. The bare
4061/// '#pragma clang attribute (attribute, subject-set)' version doesn't require a
4062/// namespace, since it always applies attributes to the most recently pushed
4063/// group, regardless of namespace.
4064/// \code
4065/// #pragma clang attribute namespace.push (attribute, subject-set)
4066/// #pragma clang attribute namespace.push
4067/// #pragma clang attribute namespace.pop
4068/// \endcode
4069///
4070/// The subject-set clause defines the set of declarations which receive the
4071/// attribute. Its exact syntax is described in the LanguageExtensions document
4072/// in Clang's documentation.
4073///
4074/// This directive instructs the compiler to begin/finish applying the specified
4075/// attribute to the set of attribute-specific declarations in the active range
4076/// of the pragma.
4077void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
4078 PragmaIntroducer Introducer,
4079 Token &FirstToken) {
4080 Token Tok;
4081 PP.Lex(Result&: Tok);
4082 auto *Info = new (PP.getPreprocessorAllocator())
4083 PragmaAttributeInfo(AttributesForPragmaAttribute);
4084
4085 // Parse the optional namespace followed by a period.
4086 if (Tok.is(K: tok::identifier)) {
4087 IdentifierInfo *II = Tok.getIdentifierInfo();
4088 if (!II->isStr(Str: "push") && !II->isStr(Str: "pop")) {
4089 Info->Namespace = II;
4090 PP.Lex(Result&: Tok);
4091
4092 if (!Tok.is(K: tok::period)) {
4093 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_attribute_expected_period)
4094 << II;
4095 return;
4096 }
4097 PP.Lex(Result&: Tok);
4098 }
4099 }
4100
4101 if (!Tok.isOneOf(Ks: tok::identifier, Ks: tok::l_paren)) {
4102 PP.Diag(Loc: Tok.getLocation(),
4103 DiagID: diag::err_pragma_attribute_expected_push_pop_paren);
4104 return;
4105 }
4106
4107 // Determine what action this pragma clang attribute represents.
4108 if (Tok.is(K: tok::l_paren)) {
4109 if (Info->Namespace) {
4110 PP.Diag(Loc: Tok.getLocation(),
4111 DiagID: diag::err_pragma_attribute_namespace_on_attribute);
4112 PP.Diag(Loc: Tok.getLocation(),
4113 DiagID: diag::note_pragma_attribute_namespace_on_attribute);
4114 return;
4115 }
4116 Info->Action = PragmaAttributeInfo::Attribute;
4117 } else {
4118 const IdentifierInfo *II = Tok.getIdentifierInfo();
4119 if (II->isStr(Str: "push"))
4120 Info->Action = PragmaAttributeInfo::Push;
4121 else if (II->isStr(Str: "pop"))
4122 Info->Action = PragmaAttributeInfo::Pop;
4123 else {
4124 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_attribute_invalid_argument)
4125 << PP.getSpelling(Tok);
4126 return;
4127 }
4128
4129 PP.Lex(Result&: Tok);
4130 }
4131
4132 // Parse the actual attribute.
4133 if ((Info->Action == PragmaAttributeInfo::Push && Tok.isNot(K: tok::eod)) ||
4134 Info->Action == PragmaAttributeInfo::Attribute) {
4135 if (Tok.isNot(K: tok::l_paren)) {
4136 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::l_paren;
4137 return;
4138 }
4139 PP.Lex(Result&: Tok);
4140
4141 // Lex the attribute tokens.
4142 SmallVector<Token, 16> AttributeTokens;
4143 int OpenParens = 1;
4144 while (Tok.isNot(K: tok::eod)) {
4145 if (Tok.is(K: tok::l_paren))
4146 OpenParens++;
4147 else if (Tok.is(K: tok::r_paren)) {
4148 OpenParens--;
4149 if (OpenParens == 0)
4150 break;
4151 }
4152
4153 AttributeTokens.push_back(Elt: Tok);
4154 PP.Lex(Result&: Tok);
4155 }
4156
4157 if (AttributeTokens.empty()) {
4158 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_attribute_expected_attribute);
4159 return;
4160 }
4161 if (Tok.isNot(K: tok::r_paren)) {
4162 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_expected) << tok::r_paren;
4163 return;
4164 }
4165 SourceLocation EndLoc = Tok.getLocation();
4166 PP.Lex(Result&: Tok);
4167
4168 // Terminate the attribute for parsing.
4169 Token EOFTok;
4170 EOFTok.startToken();
4171 EOFTok.setKind(tok::eof);
4172 EOFTok.setLocation(EndLoc);
4173 AttributeTokens.push_back(Elt: EOFTok);
4174
4175 markAsReinjectedForRelexing(Toks: AttributeTokens);
4176 Info->Tokens =
4177 llvm::ArrayRef(AttributeTokens).copy(A&: PP.getPreprocessorAllocator());
4178 }
4179
4180 if (Tok.isNot(K: tok::eod))
4181 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
4182 << "clang attribute";
4183
4184 // Generate the annotated pragma token.
4185 auto TokenArray = std::make_unique<Token[]>(num: 1);
4186 TokenArray[0].startToken();
4187 TokenArray[0].setKind(tok::annot_pragma_attribute);
4188 TokenArray[0].setLocation(FirstToken.getLocation());
4189 TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation());
4190 TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
4191 PP.EnterTokenStream(Toks: std::move(TokenArray), NumToks: 1,
4192 /*DisableMacroExpansion=*/false, /*IsReinject=*/false);
4193}
4194
4195// Handle '#pragma clang max_tokens 12345'.
4196void PragmaMaxTokensHereHandler::HandlePragma(Preprocessor &PP,
4197 PragmaIntroducer Introducer,
4198 Token &Tok) {
4199 PP.Lex(Result&: Tok);
4200 if (Tok.is(K: tok::eod)) {
4201 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_missing_argument)
4202 << "clang max_tokens_here" << /*Expected=*/true << "integer";
4203 return;
4204 }
4205
4206 SourceLocation Loc = Tok.getLocation();
4207 uint64_t MaxTokens;
4208 if (Tok.isNot(K: tok::numeric_constant) ||
4209 !PP.parseSimpleIntegerLiteral(Tok, Value&: MaxTokens)) {
4210 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_expected_integer)
4211 << "clang max_tokens_here";
4212 return;
4213 }
4214
4215 if (Tok.isNot(K: tok::eod)) {
4216 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
4217 << "clang max_tokens_here";
4218 return;
4219 }
4220
4221 if (PP.getTokenCount() > MaxTokens) {
4222 PP.Diag(Loc, DiagID: diag::warn_max_tokens)
4223 << PP.getTokenCount() << (unsigned)MaxTokens;
4224 }
4225}
4226
4227// Handle '#pragma clang max_tokens_total 12345'.
4228void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP,
4229 PragmaIntroducer Introducer,
4230 Token &Tok) {
4231 PP.Lex(Result&: Tok);
4232 if (Tok.is(K: tok::eod)) {
4233 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_missing_argument)
4234 << "clang max_tokens_total" << /*Expected=*/true << "integer";
4235 return;
4236 }
4237
4238 SourceLocation Loc = Tok.getLocation();
4239 uint64_t MaxTokens;
4240 if (Tok.isNot(K: tok::numeric_constant) ||
4241 !PP.parseSimpleIntegerLiteral(Tok, Value&: MaxTokens)) {
4242 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::err_pragma_expected_integer)
4243 << "clang max_tokens_total";
4244 return;
4245 }
4246
4247 if (Tok.isNot(K: tok::eod)) {
4248 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
4249 << "clang max_tokens_total";
4250 return;
4251 }
4252
4253 PP.overrideMaxTokens(Value: MaxTokens, Loc);
4254}
4255
4256static void zOSPragmaHandlerHelper(Preprocessor &PP, Token &Tok,
4257 tok::TokenKind TokKind) {
4258 Token AnnotTok;
4259 AnnotTok.startToken();
4260 AnnotTok.setKind(TokKind);
4261 AnnotTok.setLocation(Tok.getLocation());
4262 AnnotTok.setAnnotationEndLoc(Tok.getLocation());
4263 SmallVector<Token, 8> TokenVector;
4264 // Suck up all of the tokens before the eod.
4265 for (; Tok.isNot(K: tok::eod); PP.Lex(Result&: Tok)) {
4266 TokenVector.push_back(Elt: Tok);
4267 AnnotTok.setAnnotationEndLoc(Tok.getLocation());
4268 }
4269 // Add a sentinel EoF token to the end of the list.
4270 Token EoF;
4271 EoF.startToken();
4272 EoF.setKind(tok::eof);
4273 EoF.setLocation(Tok.getLocation());
4274 TokenVector.push_back(Elt: EoF);
4275 // We must allocate this array with new because EnterTokenStream is going to
4276 // delete it later.
4277 markAsReinjectedForRelexing(Toks: TokenVector);
4278 auto TokenArray = std::make_unique<Token[]>(num: TokenVector.size());
4279 std::copy(first: TokenVector.begin(), last: TokenVector.end(), result: TokenArray.get());
4280 auto Value = new (PP.getPreprocessorAllocator())
4281 std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray),
4282 TokenVector.size());
4283 AnnotTok.setAnnotationValue(Value);
4284 PP.EnterToken(Tok: AnnotTok, /*IsReinject*/ false);
4285}
4286
4287/// Handle #pragma export.
4288void PragmaExportHandler::HandlePragma(Preprocessor &PP,
4289 PragmaIntroducer Introducer,
4290 Token &FirstToken) {
4291 zOSPragmaHandlerHelper(PP, Tok&: FirstToken, TokKind: tok::annot_pragma_export);
4292}
4293
4294// Handle '#pragma clang riscv intrinsic vector'.
4295// '#pragma clang riscv intrinsic sifive_vector'.
4296// '#pragma clang riscv intrinsic andes_vector'.
4297void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
4298 PragmaIntroducer Introducer,
4299 Token &FirstToken) {
4300 Token Tok;
4301 PP.Lex(Result&: Tok);
4302 IdentifierInfo *II = Tok.getIdentifierInfo();
4303
4304 if (!II || !II->isStr(Str: "intrinsic")) {
4305 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_invalid_argument)
4306 << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'";
4307 return;
4308 }
4309
4310 PP.Lex(Result&: Tok);
4311 II = Tok.getIdentifierInfo();
4312 if (!II || !(II->isStr(Str: "vector") || II->isStr(Str: "sifive_vector") ||
4313 II->isStr(Str: "andes_vector"))) {
4314 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_invalid_argument)
4315 << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true
4316 << "'vector', 'sifive_vector' or 'andes_vector'";
4317 return;
4318 }
4319
4320 PP.Lex(Result&: Tok);
4321 if (Tok.isNot(K: tok::eod)) {
4322 PP.Diag(Loc: Tok.getLocation(), DiagID: diag::warn_pragma_extra_tokens_at_eol)
4323 << "clang riscv intrinsic";
4324 return;
4325 }
4326
4327 if (II->isStr(Str: "vector"))
4328 Actions.RISCV().DeclareRVVBuiltins = true;
4329 else if (II->isStr(Str: "sifive_vector"))
4330 Actions.RISCV().DeclareSiFiveVectorBuiltins = true;
4331 else if (II->isStr(Str: "andes_vector"))
4332 Actions.RISCV().DeclareAndesVectorBuiltins = true;
4333}
4334