Skip to content

Commit 8700419

Browse files
committed
Reapply "[clang][Sema] Declare builtins used in #pragma intrinsic" (#141994)"
1 parent 5301f4c commit 8700419

File tree

5 files changed

+123
-58
lines changed

5 files changed

+123
-58
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7074,6 +7074,10 @@ class Parser : public CodeCompletionHandler {
70747074
bool HandlePragmaMSOptimize(StringRef PragmaName,
70757075
SourceLocation PragmaLocation);
70767076

7077+
// #pragma intrinsic("foo")
7078+
bool HandlePragmaMSIntrinsic(StringRef PragmaName,
7079+
SourceLocation PragmaLocation);
7080+
70777081
/// Handle the annotation token produced for
70787082
/// #pragma align...
70797083
void HandlePragmaAlign();

clang/lib/Parse/ParsePragma.cpp

Lines changed: 53 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,6 @@ struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler {
300300
PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {}
301301
};
302302

303-
struct PragmaMSIntrinsicHandler : public PragmaHandler {
304-
PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {}
305-
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
306-
Token &FirstToken) override;
307-
};
308-
309303
// "\#pragma fenv_access (on)".
310304
struct PragmaMSFenvAccessHandler : public PragmaHandler {
311305
PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {}
@@ -517,7 +511,7 @@ void Parser::initializePragmaHandlers() {
517511
PP.AddPragmaHandler(MSOptimize.get());
518512
MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
519513
PP.AddPragmaHandler(MSRuntimeChecks.get());
520-
MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>();
514+
MSIntrinsic = std::make_unique<PragmaMSPragma>("intrinsic");
521515
PP.AddPragmaHandler(MSIntrinsic.get());
522516
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
523517
PP.AddPragmaHandler(MSFenvAccess.get());
@@ -1046,7 +1040,8 @@ void Parser::HandlePragmaMSPragma() {
10461040
.Case("strict_gs_check", &Parser::HandlePragmaMSStrictGuardStackCheck)
10471041
.Case("function", &Parser::HandlePragmaMSFunction)
10481042
.Case("alloc_text", &Parser::HandlePragmaMSAllocText)
1049-
.Case("optimize", &Parser::HandlePragmaMSOptimize);
1043+
.Case("optimize", &Parser::HandlePragmaMSOptimize)
1044+
.Case("intrinsic", &Parser::HandlePragmaMSIntrinsic);
10501045

10511046
if (!(this->*Handler)(PragmaName, PragmaLocation)) {
10521047
// Pragma handling failed, and has been diagnosed. Slurp up the tokens
@@ -3762,56 +3757,6 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
37623757
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
37633758
}
37643759

3765-
/// Handle the Microsoft \#pragma intrinsic extension.
3766-
///
3767-
/// The syntax is:
3768-
/// \code
3769-
/// #pragma intrinsic(memset)
3770-
/// #pragma intrinsic(strlen, memcpy)
3771-
/// \endcode
3772-
///
3773-
/// Pragma intrisic tells the compiler to use a builtin version of the
3774-
/// function. Clang does it anyway, so the pragma doesn't really do anything.
3775-
/// Anyway, we emit a warning if the function specified in \#pragma intrinsic
3776-
/// isn't an intrinsic in clang and suggest to include intrin.h.
3777-
void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP,
3778-
PragmaIntroducer Introducer,
3779-
Token &Tok) {
3780-
PP.Lex(Tok);
3781-
3782-
if (Tok.isNot(tok::l_paren)) {
3783-
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
3784-
<< "intrinsic";
3785-
return;
3786-
}
3787-
PP.Lex(Tok);
3788-
3789-
bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
3790-
3791-
while (Tok.is(tok::identifier)) {
3792-
IdentifierInfo *II = Tok.getIdentifierInfo();
3793-
if (!II->getBuiltinID())
3794-
PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
3795-
<< II << SuggestIntrinH;
3796-
3797-
PP.Lex(Tok);
3798-
if (Tok.isNot(tok::comma))
3799-
break;
3800-
PP.Lex(Tok);
3801-
}
3802-
3803-
if (Tok.isNot(tok::r_paren)) {
3804-
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
3805-
<< "intrinsic";
3806-
return;
3807-
}
3808-
PP.Lex(Tok);
3809-
3810-
if (Tok.isNot(tok::eod))
3811-
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
3812-
<< "intrinsic";
3813-
}
3814-
38153760
bool Parser::HandlePragmaMSFunction(StringRef PragmaName,
38163761
SourceLocation PragmaLocation) {
38173762
Token FirstTok = Tok;
@@ -3907,6 +3852,56 @@ bool Parser::HandlePragmaMSOptimize(StringRef PragmaName,
39073852
return true;
39083853
}
39093854

3855+
/// Handle the Microsoft \#pragma intrinsic extension.
3856+
///
3857+
/// The syntax is:
3858+
/// \code
3859+
/// #pragma intrinsic(memset)
3860+
/// #pragma intrinsic(strlen, memcpy)
3861+
/// \endcode
3862+
///
3863+
/// Pragma intrisic tells the compiler to use a builtin version of the
3864+
/// function. Clang does it anyway, so the pragma doesn't really do anything.
3865+
/// Anyway, we emit a warning if the function specified in \#pragma intrinsic
3866+
/// isn't an intrinsic in clang and suggest to include intrin.h, as well as
3867+
/// declare the builtin if it has not been declared.
3868+
bool Parser::HandlePragmaMSIntrinsic(StringRef PragmaName,
3869+
SourceLocation PragmaLocation) {
3870+
if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
3871+
PragmaName))
3872+
return false;
3873+
3874+
bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
3875+
3876+
while (Tok.is(tok::identifier)) {
3877+
IdentifierInfo *II = Tok.getIdentifierInfo();
3878+
if (!II->getBuiltinID())
3879+
PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
3880+
<< II << SuggestIntrinH;
3881+
// If the builtin hasn't already been declared, declare it now.
3882+
DeclarationNameInfo NameInfo(II, Tok.getLocation());
3883+
LookupResult Previous(Actions, NameInfo, Sema::LookupOrdinaryName,
3884+
RedeclarationKind::NotForRedeclaration);
3885+
Actions.LookupName(Previous, Actions.getCurScope(),
3886+
/*CreateBuiltins*/ false);
3887+
if (Previous.empty())
3888+
Actions.LazilyCreateBuiltin(II, II->getBuiltinID(), Actions.getCurScope(),
3889+
/*ForRedeclaration*/ true, Tok.getLocation());
3890+
PP.Lex(Tok);
3891+
if (Tok.isNot(tok::comma))
3892+
break;
3893+
PP.Lex(Tok);
3894+
}
3895+
if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
3896+
PragmaName))
3897+
return false;
3898+
3899+
if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
3900+
PragmaName))
3901+
return false;
3902+
return true;
3903+
}
3904+
39103905
void PragmaForceCUDAHostDeviceHandler::HandlePragma(
39113906
Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) {
39123907
Token FirstTok = Tok;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifdef USE_PRAGMA_BEFORE
2+
#pragma intrinsic(_InterlockedOr64)
3+
#endif
4+
5+
#define MACRO(x,y) _InterlockedOr64(x,y);
6+
7+
#ifdef USE_PRAGMA_AFTER
8+
#pragma intrinsic(_InterlockedOr64)
9+
#endif
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DOUTSIDE %s
2+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DINSIDE %s
3+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DNESTED %s
4+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DOUTSIDE -DEXTERN %s
5+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DINSIDE -DEXTERN %s
6+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-compatibility -fsyntax-only -verify -DNESTED -DEXTERN %s
7+
8+
// expected-no-diagnostics
9+
#ifdef EXTERN
10+
extern "C"
11+
#endif
12+
unsigned __int64 _umul128(unsigned __int64, unsigned __int64,
13+
unsigned __int64 *);
14+
namespace {
15+
#ifdef INSIDE
16+
#pragma intrinsic(_umul128)
17+
#endif
18+
#ifdef NESTED
19+
namespace {
20+
#pragma intrinsic(_umul128)
21+
}
22+
#endif
23+
}
24+
25+
#ifdef OUTSIDE
26+
#pragma intrinsic(_umul128)
27+
#endif
28+
29+
void foo() {
30+
unsigned __int64 carry;
31+
unsigned __int64 low = _umul128(0, 0, &carry);
32+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_BEFORE
2+
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_AFTER
3+
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_AFTER_USE
4+
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s -DUSE_PRAGMA_SAME_FILE
5+
// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify -triple arm64-windows -isystem %S/Inputs %s
6+
7+
#if defined(USE_PRAGMA_BEFORE) || defined(USE_PRAGMA_AFTER) || defined(USE_PRAGMA_SAME_FILE)
8+
// expected-no-diagnostics
9+
#else
10+
// expected-error@+10 {{call to undeclared library function '_InterlockedOr64'}}
11+
// expected-note@+9 {{include the header <intrin.h> or explicitly provide a declaration for '_InterlockedOr64'}}
12+
#endif
13+
#include <builtin-system-header.h>
14+
15+
#ifdef USE_PRAGMA_SAME_FILE
16+
#pragma intrinsic(_InterlockedOr64)
17+
#endif
18+
19+
void foo() {
20+
MACRO(0,0);
21+
}
22+
23+
#ifdef USE_PRAGMA_AFTER_USE
24+
#pragma intrinsic(_InterlockedOr64)
25+
#endif

0 commit comments

Comments
 (0)