[clang] [clang][Parser] Fix lookup of builtins with pragma intrinsic (PR #142019)
Nick Sarnie via cfe-commits
cfe-commits at lists.llvm.org
Fri May 30 08:25:34 PDT 2025
https://github.com/sarnex updated https://github.com/llvm/llvm-project/pull/142019
>From 3cf1fcb8cc722bd60a91034d9ef47240bea6a751 Mon Sep 17 00:00:00 2001
From: "Sarnie, Nick" <nick.sarnie at intel.com>
Date: Fri, 30 May 2025 08:09:45 -0700
Subject: [PATCH] Reapply "[clang][Sema] Declare builtins used in #pragma
intrinsic" (#141994)"
---
clang/include/clang/Parse/Parser.h | 4 +
clang/lib/Parse/ParsePragma.cpp | 111 +++++++++---------
.../test/Sema/Inputs/builtin-system-header.h | 9 ++
.../builtin-pragma-intrinsic-namespace.cpp | 14 +++
clang/test/Sema/builtin-pragma-intrinsic.c | 25 ++++
5 files changed, 105 insertions(+), 58 deletions(-)
create mode 100644 clang/test/Sema/Inputs/builtin-system-header.h
create mode 100644 clang/test/Sema/builtin-pragma-intrinsic-namespace.cpp
create mode 100644 clang/test/Sema/builtin-pragma-intrinsic.c
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index c4bef4729fd36..98db8201390be 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7074,6 +7074,10 @@ class Parser : public CodeCompletionHandler {
bool HandlePragmaMSOptimize(StringRef PragmaName,
SourceLocation PragmaLocation);
+ // #pragma intrinsic("foo")
+ bool HandlePragmaMSIntrinsic(StringRef PragmaName,
+ SourceLocation PragmaLocation);
+
/// Handle the annotation token produced for
/// #pragma align...
void HandlePragmaAlign();
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 77b61af768993..052d77d6389a1 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -300,12 +300,6 @@ struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler {
PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {}
};
-struct PragmaMSIntrinsicHandler : public PragmaHandler {
- PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {}
- void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
- Token &FirstToken) override;
-};
-
// "\#pragma fenv_access (on)".
struct PragmaMSFenvAccessHandler : public PragmaHandler {
PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {}
@@ -517,7 +511,7 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(MSOptimize.get());
MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
PP.AddPragmaHandler(MSRuntimeChecks.get());
- MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>();
+ MSIntrinsic = std::make_unique<PragmaMSPragma>("intrinsic");
PP.AddPragmaHandler(MSIntrinsic.get());
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
PP.AddPragmaHandler(MSFenvAccess.get());
@@ -1046,7 +1040,8 @@ void Parser::HandlePragmaMSPragma() {
.Case("strict_gs_check", &Parser::HandlePragmaMSStrictGuardStackCheck)
.Case("function", &Parser::HandlePragmaMSFunction)
.Case("alloc_text", &Parser::HandlePragmaMSAllocText)
- .Case("optimize", &Parser::HandlePragmaMSOptimize);
+ .Case("optimize", &Parser::HandlePragmaMSOptimize)
+ .Case("intrinsic", &Parser::HandlePragmaMSIntrinsic);
if (!(this->*Handler)(PragmaName, PragmaLocation)) {
// Pragma handling failed, and has been diagnosed. Slurp up the tokens
@@ -3762,56 +3757,6 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
}
-/// Handle the Microsoft \#pragma intrinsic extension.
-///
-/// The syntax is:
-/// \code
-/// #pragma intrinsic(memset)
-/// #pragma intrinsic(strlen, memcpy)
-/// \endcode
-///
-/// Pragma intrisic tells the compiler to use a builtin version of the
-/// function. Clang does it anyway, so the pragma doesn't really do anything.
-/// Anyway, we emit a warning if the function specified in \#pragma intrinsic
-/// isn't an intrinsic in clang and suggest to include intrin.h.
-void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP,
- PragmaIntroducer Introducer,
- Token &Tok) {
- PP.Lex(Tok);
-
- if (Tok.isNot(tok::l_paren)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
- << "intrinsic";
- return;
- }
- PP.Lex(Tok);
-
- bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
-
- while (Tok.is(tok::identifier)) {
- IdentifierInfo *II = Tok.getIdentifierInfo();
- if (!II->getBuiltinID())
- PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
- << II << SuggestIntrinH;
-
- PP.Lex(Tok);
- if (Tok.isNot(tok::comma))
- break;
- PP.Lex(Tok);
- }
-
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
- << "intrinsic";
- return;
- }
- PP.Lex(Tok);
-
- if (Tok.isNot(tok::eod))
- PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
- << "intrinsic";
-}
-
bool Parser::HandlePragmaMSFunction(StringRef PragmaName,
SourceLocation PragmaLocation) {
Token FirstTok = Tok;
@@ -3907,6 +3852,56 @@ bool Parser::HandlePragmaMSOptimize(StringRef PragmaName,
return true;
}
+/// Handle the Microsoft \#pragma intrinsic extension.
+///
+/// The syntax is:
+/// \code
+/// #pragma intrinsic(memset)
+/// #pragma intrinsic(strlen, memcpy)
+/// \endcode
+///
+/// Pragma intrisic tells the compiler to use a builtin version of the
+/// function. Clang does it anyway, so the pragma doesn't really do anything.
+/// Anyway, we emit a warning if the function specified in \#pragma intrinsic
+/// isn't an intrinsic in clang and suggest to include intrin.h, as well as
+/// declare the builtin if it has not been declared.
+bool Parser::HandlePragmaMSIntrinsic(StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
+
+ bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
+
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->getBuiltinID())
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
+ << II << SuggestIntrinH;
+ // If the builtin hasn't already been declared, declare it now.
+ DeclarationNameInfo NameInfo(II, Tok.getLocation());
+ LookupResult Previous(Actions, NameInfo, Sema::LookupOrdinaryName,
+ Actions.forRedeclarationInCurContext());
+ Actions.LookupName(Previous, Actions.getCurScope(),
+ /*CreateBuiltins*/ false);
+ if (Previous.empty())
+ Actions.LazilyCreateBuiltin(II, II->getBuiltinID(), Actions.getCurScope(),
+ /*ForRedeclaration*/ true, Tok.getLocation());
+ PP.Lex(Tok);
+ if (Tok.isNot(tok::comma))
+ break;
+ PP.Lex(Tok);
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName))
+ return false;
+
+ if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+ return true;
+}
+
void PragmaForceCUDAHostDeviceHandler::HandlePragma(
Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) {
Token FirstTok = Tok;
diff --git a/clang/test/Sema/Inputs/builtin-system-header.h b/clang/test/Sema/Inputs/builtin-system-header.h
new file mode 100644
index 0000000000000..7eeb8d811fcfa
--- /dev/null
+++ b/clang/test/Sema/Inputs/builtin-system-header.h
@@ -0,0 +1,9 @@
+#ifdef USE_PRAGMA_BEFORE
+#pragma intrinsic(_InterlockedOr64)
+#endif
+
+#define MACRO(x,y) _InterlockedOr64(x,y);
+
+#ifdef USE_PRAGMA_AFTER
+#pragma intrinsic(_InterlockedOr64)
+#endif
diff --git a/clang/test/Sema/builtin-pragma-intrinsic-namespace.cpp b/clang/test/Sema/builtin-pragma-intrinsic-namespace.cpp
new file mode 100644
index 0000000000000..534efbdcaa970
--- /dev/null
+++ b/clang/test/Sema/builtin-pragma-intrinsic-namespace.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+unsigned __int64 _umul128(unsigned __int64, unsigned __int64,
+ unsigned __int64 *);
+
+namespace {}
+#pragma intrinsic(_umul128)
+
+ void foo() {
+ unsigned __int64 carry;
+ unsigned __int64 low = _umul128(0, 0, &carry);
+ }
diff --git a/clang/test/Sema/builtin-pragma-intrinsic.c b/clang/test/Sema/builtin-pragma-intrinsic.c
new file mode 100644
index 0000000000000..1e8507bfd37df
--- /dev/null
+++ b/clang/test/Sema/builtin-pragma-intrinsic.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_BEFORE
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_AFTER
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_AFTER_USE
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_SAME_FILE
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s
+
+#if defined(USE_PRAGMA_BEFORE) || defined(USE_PRAGMA_AFTER) || defined(USE_PRAGMA_SAME_FILE)
+// expected-no-diagnostics
+#else
+// expected-error at +10 {{call to undeclared library function '_InterlockedOr64'}}
+// expected-note at +9 {{include the header <intrin.h> or explicitly provide a declaration for '_InterlockedOr64'}}
+#endif
+#include <builtin-system-header.h>
+
+#ifdef USE_PRAGMA_SAME_FILE
+#pragma intrinsic(_InterlockedOr64)
+#endif
+
+void foo() {
+ MACRO(0,0);
+}
+
+#ifdef USE_PRAGMA_AFTER_USE
+#pragma intrinsic(_InterlockedOr64)
+#endif
More information about the cfe-commits
mailing list