steplong updated this revision to Diff 427127.
steplong added a comment.
Error if pragma function/intrinsic is used inside a function
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D124702/new/
https://reviews.llvm.org/D124702
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParsePragma.cpp
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/CodeGen/pragma-ms-function-intrinsic.c
Index: clang/test/CodeGen/pragma-ms-function-intrinsic.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/pragma-ms-function-intrinsic.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -emit-llvm -fms-extensions -o - %s | FileCheck %s
+
+typedef typeof(sizeof(0)) size_t;
+
+void bar(char *s);
+void *memset(void *s, int c, size_t n);
+void *memcpy(void *d, const void *s, size_t n);
+
+// CHECK: define{{.*}} void @foo1({{.*}}) #[[NO_NOBUILTIN:[0-9]+]]
+// CHECK: call void @bar
+// CHECK: call void @llvm.memset
+// CHECK: call void @llvm.memcpy
+void foo1(char *s, char *d, size_t n)
+{
+ bar(s);
+ memset(s, 0, n);
+ memcpy(d, s, n);
+}
+
+#pragma function(strlen, memset)
+
+// CHECK: define{{.*}} void @foo2({{.*}}) #[[NOBUILTIN_MEMSET:[0-9]+]]
+// CHECK: call void @bar
+// CHECK: {{.*}}call {{.*}} @memset
+// CHECK: call void @llvm.memcpy
+void foo2(char *s, char *d, size_t n)
+{
+ bar(s);
+ memset(s, 1, n);
+ memcpy(d, s, n);
+}
+
+#pragma function(memcpy)
+
+// CHECK: define{{.*}} void @foo3({{.*}}) #[[NOBUILTIN_MEMSET_MEMCPY:[0-9]+]]
+// CHECK: call void @bar
+// CHECK: {{.*}}call {{.*}} @memset
+// CHECK: {{.*}}call {{.*}} @memcpy
+void foo3(char *s, char *d, size_t n)
+{
+ bar(s);
+ memset(s, 2, n);
+ memcpy(d, s, n);
+}
+
+#pragma intrinsic(memset, strlen)
+
+// CHECK: define{{.*}} void @foo4({{.*}}) #[[NOBUILTIN_MEMCPY:[0-9]+]]
+// CHECK: call void @bar
+// CHECK: call void @llvm.memset
+// CHECK: {{.*}}call {{.*}} @memcpy
+void foo4(char *s, char *d, size_t n)
+{
+ bar(s);
+ memset(s, 3, n);
+ memcpy(d, s, n);
+}
+
+#pragma intrinsic(memcpy)
+
+// CHECK: define{{.*}} void @foo5({{.*}}) #[[NO_NOBUILTIN]]
+// CHECK: call void @bar
+// CHECK: call void @llvm.memset
+// CHECK: call void @llvm.memcpy
+void foo5(char *s, char *d, size_t n)
+{
+ bar(s);
+ memset(s, 4, n);
+ memcpy(d, s, n);
+}
+
+// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memset"{{.*}}}
+// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
+// CHECK: attributes #[[NOBUILTIN_MEMSET]] = {{{.*}}"no-builtin-memset"{{.*}}}
+// CHECK-NOT: attributes #[[NOBUILTIN_MEMSET]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
+// CHECK: attributes #[[NOBUILTIN_MEMSET_MEMCPY]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
+// CHECK: attributes #[[NOBUILTIN_MEMCPY]] = {{{.*}}"no-builtin-memcpy"{{.*}}}
+// CHECK-NOT: attributes #[[NOBUILTIN_MEMCPY]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}}
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -10218,10 +10218,12 @@
// marking the function.
AddCFAuditedAttribute(NewFD);
- // If this is a function definition, check if we have to apply optnone due to
- // a pragma.
- if(D.isFunctionDefinition())
+ // If this is a function definition, check if we have to apply any
+ // attributes (i.e. optnone and no_builtin) due to a pragma.
+ if(D.isFunctionDefinition()) {
AddRangeBasedOptnone(NewFD);
+ AddRangeBasedNoBuiltin(NewFD);
+ }
// If this is the first declaration of an extern C variable, update
// the map of such variables.
Index: clang/lib/Sema/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -1065,6 +1065,31 @@
OptimizeOffPragmaLocation = PragmaLoc;
}
+void Sema::ActOnPragmaMSIntrinsic(
+ SourceLocation Loc, const SmallVectorImpl<StringRef> &Intrinsics) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(Loc, diag::err_pragma_intrinsic_function_scope);
+ return;
+ }
+
+ for (auto &Intrinsic : Intrinsics)
+ MSFunctionNoBuiltins.erase(std::remove(MSFunctionNoBuiltins.begin(),
+ MSFunctionNoBuiltins.end(),
+ Intrinsic),
+ MSFunctionNoBuiltins.end());
+}
+
+void Sema::ActOnPragmaMSFunction(SourceLocation Loc,
+ const SmallVectorImpl<StringRef> &NoBuiltins) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(Loc, diag::err_pragma_intrinsic_function_scope);
+ return;
+ }
+
+ MSFunctionNoBuiltins.insert(MSFunctionNoBuiltins.end(),
+ NoBuiltins.begin(), NoBuiltins.end());
+}
+
void Sema::AddRangeBasedOptnone(FunctionDecl *FD) {
// In the future, check other pragmas if they're implemented (e.g. pragma
// optimize 0 will probably map to this functionality too).
@@ -1086,6 +1111,12 @@
FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc));
}
+void Sema::AddRangeBasedNoBuiltin(FunctionDecl *FD) {
+ if (!MSFunctionNoBuiltins.empty())
+ FD->addAttr(NoBuiltinAttr::CreateImplicit(Context,
+ MSFunctionNoBuiltins.data(), MSFunctionNoBuiltins.size()));
+}
+
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
enum : unsigned { NoVisibility = ~0U };
Index: clang/lib/Parse/ParsePragma.cpp
===================================================================
--- clang/lib/Parse/ParsePragma.cpp
+++ clang/lib/Parse/ParsePragma.cpp
@@ -250,9 +250,21 @@
};
struct PragmaMSIntrinsicHandler : public PragmaHandler {
- PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {}
+ PragmaMSIntrinsicHandler(Sema &S) : PragmaHandler("intrinsic"), Actions(S) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &FirstToken) override;
+
+private:
+ Sema &Actions;
+};
+
+struct PragmaMSFunctionHandler : public PragmaHandler {
+ PragmaMSFunctionHandler(Sema &S) : PragmaHandler("function"), Actions(S) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
+ Token &FirstToken) override;
+
+private:
+ Sema &Actions;
};
struct PragmaMSOptimizeHandler : public PragmaHandler {
@@ -447,8 +459,10 @@
PP.AddPragmaHandler(MSSection.get());
MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
PP.AddPragmaHandler(MSRuntimeChecks.get());
- MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>();
+ MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>(Actions);
PP.AddPragmaHandler(MSIntrinsic.get());
+ MSFunction = std::make_unique<PragmaMSFunctionHandler>(Actions);
+ PP.AddPragmaHandler(MSFunction.get());
MSOptimize = std::make_unique<PragmaMSOptimizeHandler>();
PP.AddPragmaHandler(MSOptimize.get());
MSFenvAccess = std::make_unique<PragmaMSFenvAccessHandler>();
@@ -558,6 +572,8 @@
MSRuntimeChecks.reset();
PP.RemovePragmaHandler(MSIntrinsic.get());
MSIntrinsic.reset();
+ PP.RemovePragmaHandler(MSFunction.get());
+ MSFunction.reset();
PP.RemovePragmaHandler(MSOptimize.get());
MSOptimize.reset();
PP.RemovePragmaHandler(MSFenvAccess.get());
@@ -3512,6 +3528,7 @@
void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &Tok) {
+ Token FirstTok = Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
@@ -3523,11 +3540,14 @@
bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
+ SmallVector<StringRef> Intrinsics;
while (Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
if (!II->getBuiltinID())
PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
<< II << SuggestIntrinH;
+ else
+ Intrinsics.emplace_back(II->getName());
PP.Lex(Tok);
if (Tok.isNot(tok::comma))
@@ -3545,6 +3565,52 @@
if (Tok.isNot(tok::eod))
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "intrinsic";
+
+ Actions.ActOnPragmaMSIntrinsic(FirstTok.getLocation(), Intrinsics);
+}
+
+void PragmaMSFunctionHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducer Introducer,
+ Token &Tok) {
+ Token FirstTok = Tok;
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
+ << "function";
+ return;
+ }
+ PP.Lex(Tok); // (
+
+ bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H");
+
+ SmallVector<StringRef> NoBuiltins;
+ while (Tok.is(tok::identifier)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (!II->getBuiltinID())
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin)
+ << II << SuggestIntrinH;
+ else
+ NoBuiltins.emplace_back(II->getName());
+
+ 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)
+ << "function";
+ return;
+ }
+ PP.Lex(Tok); // )
+
+ if (Tok.isNot(tok::eod))
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << "function";
+
+ Actions.ActOnPragmaMSFunction(FirstTok.getLocation(), NoBuiltins);
}
// #pragma optimize("gsty", on|off)
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -755,6 +755,8 @@
/// optimizations are currently "on", this is set to an invalid location.
SourceLocation OptimizeOffPragmaLocation;
+ SmallVector<StringRef> MSFunctionNoBuiltins;
+
/// Flag indicating if Sema is building a recovery call expression.
///
/// This flag is used to avoid building recovery call expressions
@@ -10314,6 +10316,12 @@
/// Called on well formed \#pragma clang optimize.
void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc);
+ void ActOnPragmaMSIntrinsic(SourceLocation Loc,
+ const SmallVectorImpl<StringRef> &Intrinsics);
+
+ void ActOnPragmaMSFunction(SourceLocation Loc,
+ const SmallVectorImpl<StringRef> &NoBuiltins);
+
/// Get the location for the currently active "\#pragma clang optimize
/// off". If this location is invalid, then the state of the pragma is "on".
SourceLocation getOptimizeOffPragmaLocation() const {
@@ -10330,6 +10338,11 @@
/// attribute to be added (usually because of a pragma).
void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc);
+ /// Only called on function definitions; if there is a pragma in scope
+ /// with the effect of a range-based no_builtin, consider marking the function
+ /// with attribute no_builtin.
+ void AddRangeBasedNoBuiltin(FunctionDecl *FD);
+
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
bool IsPackExpansion);
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -196,6 +196,7 @@
std::unique_ptr<PragmaHandler> MSSection;
std::unique_ptr<PragmaHandler> MSRuntimeChecks;
std::unique_ptr<PragmaHandler> MSIntrinsic;
+ std::unique_ptr<PragmaHandler> MSFunction;
std::unique_ptr<PragmaHandler> MSOptimize;
std::unique_ptr<PragmaHandler> MSFenvAccess;
std::unique_ptr<PragmaHandler> CUDAForceHostDeviceHandler;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -984,6 +984,9 @@
def err_super_in_lambda_unsupported : Error<
"use of '__super' inside a lambda is unsupported">;
+def err_pragma_intrinsic_function_scope : Error<
+ "'#pragma function/intrinsic' can only appear outside a function, at the global level">;
+
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
InGroup<IgnoredPragmas>;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits