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