Skip to content

Commit 70f1cb6

Browse files
committed
Add optimization mode for builtin nonnull attribute
Introduce two modes for the builtin nonnull attribute. Instead of always emitting the GNU-style `nonnull` attribute, Clang now distinguishes between: * NonOptimizing: attaches Clang's `_Nonnull` type qualifier. * Optimizing: emits GNU-style `nonnull` attribute.
1 parent 265c9a6 commit 70f1cb6

File tree

6 files changed

+66
-30
lines changed

6 files changed

+66
-30
lines changed

clang/include/clang/Basic/Builtins.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ struct Info {
9494
///
9595
/// Must be provided the `Shard` for this `Info` object.
9696
std::string getName(const InfosShard &Shard) const;
97+
98+
// Builtin non-null attribute modes.
99+
// NonOptimizing: attaches Clang's `_Nonnull` type qualifier to parameters.
100+
// Optimizing: emits the classic GNU-style `nonnull` attribute for
101+
// optimization.
102+
enum class NonNullMode { NonOptimizing, Optimizing };
97103
};
98104

99105
/// A constexpr function to construct an infos array from X-macros.
@@ -394,7 +400,8 @@ class Context {
394400

395401
/// Return true if this builtin has parameters that must be non-null.
396402
/// The parameter indices are appended into 'Indxs'.
397-
bool isNonNull(unsigned ID, llvm::SmallVectorImpl<int> &Indxs) const;
403+
bool isNonNull(unsigned ID, llvm::SmallVectorImpl<int> &Indxs,
404+
Info::NonNullMode &Mode) const;
398405

399406
/// Return true if this function has no side effects and doesn't
400407
/// read memory, except for possibly errno or raising FP exceptions.

clang/include/clang/Basic/Builtins.td

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3095,105 +3095,105 @@ def StrLen : LibBuiltin<"string.h"> {
30953095
// FIXME: This list is incomplete.
30963096
def Printf : LibBuiltin<"stdio.h"> {
30973097
let Spellings = ["printf"];
3098-
let Attributes = [PrintfFormat<0>, NonNull<[0]>];
3098+
let Attributes = [PrintfFormat<0>, NonNull<NonOptimizing, [0]>];
30993099
let Prototype = "int(char const*, ...)";
31003100
}
31013101

31023102
// FIXME: The builtin and library function should have the same signature.
31033103
def BuiltinPrintf : Builtin {
31043104
let Spellings = ["__builtin_printf"];
31053105
let Attributes = [NoThrow, PrintfFormat<0>, FunctionWithBuiltinPrefix,
3106-
NonNull<[0]>];
3106+
NonNull<NonOptimizing, [0]>];
31073107
let Prototype = "int(char const* restrict, ...)";
31083108
}
31093109

31103110
def FPrintf : LibBuiltin<"stdio.h"> {
31113111
let Spellings = ["fprintf"];
3112-
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[0, 1]>];
3112+
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31133113
let Prototype = "int(FILE* restrict, char const* restrict, ...)";
31143114
let AddBuiltinPrefixedAlias = 1;
31153115
}
31163116

31173117
def SnPrintf : LibBuiltin<"stdio.h"> {
31183118
let Spellings = ["snprintf"];
3119-
let Attributes = [NoThrow, PrintfFormat<2>, NonNull<[2]>];
3119+
let Attributes = [NoThrow, PrintfFormat<2>, NonNull<NonOptimizing, [2]>];
31203120
let Prototype = "int(char* restrict, size_t, char const* restrict, ...)";
31213121
let AddBuiltinPrefixedAlias = 1;
31223122
}
31233123

31243124
def SPrintf : LibBuiltin<"stdio.h"> {
31253125
let Spellings = ["sprintf"];
3126-
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<[0, 1]>];
3126+
let Attributes = [NoThrow, PrintfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31273127
let Prototype = "int(char* restrict, char const* restrict, ...)";
31283128
let AddBuiltinPrefixedAlias = 1;
31293129
}
31303130

31313131
def VPrintf : LibBuiltin<"stdio.h"> {
31323132
let Spellings = ["vprintf"];
3133-
let Attributes = [NoThrow, VPrintfFormat<0>, NonNull<[0]>];
3133+
let Attributes = [NoThrow, VPrintfFormat<0>, NonNull<NonOptimizing, [0]>];
31343134
let Prototype = "int(char const* restrict, __builtin_va_list)";
31353135
let AddBuiltinPrefixedAlias = 1;
31363136
}
31373137

31383138
def VfPrintf : LibBuiltin<"stdio.h"> {
31393139
let Spellings = ["vfprintf"];
3140-
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[0, 1]>];
3140+
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31413141
let Prototype = "int(FILE* restrict, char const* restrict, __builtin_va_list)";
31423142
let AddBuiltinPrefixedAlias = 1;
31433143
}
31443144

31453145
def VsnPrintf : LibBuiltin<"stdio.h"> {
31463146
let Spellings = ["vsnprintf"];
3147-
let Attributes = [NoThrow, VPrintfFormat<2>, NonNull<[2]>];
3147+
let Attributes = [NoThrow, VPrintfFormat<2>, NonNull<NonOptimizing, [2]>];
31483148
let Prototype = "int(char* restrict, size_t, char const* restrict, __builtin_va_list)";
31493149
let AddBuiltinPrefixedAlias = 1;
31503150
}
31513151

31523152
def VsPrintf : LibBuiltin<"stdio.h"> {
31533153
let Spellings = ["vsprintf"];
3154-
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<[0, 1]>];
3154+
let Attributes = [NoThrow, VPrintfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31553155
let Prototype = "int(char* restrict, char const* restrict, __builtin_va_list)";
31563156
let AddBuiltinPrefixedAlias = 1;
31573157
}
31583158

31593159
def Scanf : LibBuiltin<"stdio.h"> {
31603160
let Spellings = ["scanf"];
3161-
let Attributes = [ScanfFormat<0>, NonNull<[0]>];
3161+
let Attributes = [ScanfFormat<0>, NonNull<NonOptimizing, [0]>];
31623162
let Prototype = "int(char const* restrict, ...)";
31633163
let AddBuiltinPrefixedAlias = 1;
31643164
}
31653165

31663166
def FScanf : LibBuiltin<"stdio.h"> {
31673167
let Spellings = ["fscanf"];
3168-
let Attributes = [ScanfFormat<1>, NonNull<[0, 1]>];
3168+
let Attributes = [ScanfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31693169
let Prototype = "int(FILE* restrict, char const* restrict, ...)";
31703170
let AddBuiltinPrefixedAlias = 1;
31713171
}
31723172

31733173
def SScanf : LibBuiltin<"stdio.h"> {
31743174
let Spellings = ["sscanf"];
3175-
let Attributes = [ScanfFormat<1>, NonNull<[0, 1]>];
3175+
let Attributes = [ScanfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31763176
let Prototype = "int(char const* restrict, char const* restrict, ...)";
31773177
let AddBuiltinPrefixedAlias = 1;
31783178
}
31793179

31803180
def VScanf : LibBuiltin<"stdio.h"> {
31813181
let Spellings = ["vscanf"];
3182-
let Attributes = [VScanfFormat<0>, NonNull<[0]>];
3182+
let Attributes = [VScanfFormat<0>, NonNull<NonOptimizing, [0]>];
31833183
let Prototype = "int(char const* restrict, __builtin_va_list)";
31843184
let AddBuiltinPrefixedAlias = 1;
31853185
}
31863186

31873187
def VFScanf : LibBuiltin<"stdio.h"> {
31883188
let Spellings = ["vfscanf"];
3189-
let Attributes = [VScanfFormat<1>, NonNull<[0, 1]>];
3189+
let Attributes = [VScanfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31903190
let Prototype = "int(FILE* restrict, char const* restrict, __builtin_va_list)";
31913191
let AddBuiltinPrefixedAlias = 1;
31923192
}
31933193

31943194
def VSScanf : LibBuiltin<"stdio.h"> {
31953195
let Spellings = ["vsscanf"];
3196-
let Attributes = [VScanfFormat<1>, NonNull<[0, 1]>];
3196+
let Attributes = [VScanfFormat<1>, NonNull<NonOptimizing, [0, 1]>];
31973197
let Prototype = "int(char const* restrict, char const* restrict, __builtin_va_list)";
31983198
let AddBuiltinPrefixedAlias = 1;
31993199
}

clang/include/clang/Basic/BuiltinsBase.td

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ def NoThrow : Attribute<"n">;
3333
def Pure : Attribute<"U">;
3434
def ReturnsTwice : Attribute<"j">;
3535

36+
class NonNullOptMode {
37+
int value;
38+
}
39+
40+
def NonOptimizing : NonNullOptMode { let value = 0; }
41+
def Optimizing : NonNullOptMode { let value = 1; }
42+
43+
class NonNull<NonNullOptMode Mode, list<int> Is> : MultiIndexAttribute<"N", Is> {
44+
int optMode = Mode.value;
45+
let Mangling = "N:" # Mode.value # ":";
46+
}
47+
3648
// builtin-specific attributes
3749
// ---------------------------
3850

@@ -84,7 +96,6 @@ def Consteval : Attribute<"EG">;
8496
// Callback behavior: the first index argument is called with the arguments
8597
// indicated by the remaining indices.
8698
class Callback<list<int> ArgIndices> : MultiIndexAttribute<"C", ArgIndices>;
87-
class NonNull<list<int> ArgIndices> : MultiIndexAttribute<"N", ArgIndices>;
8899

89100
// Prefixes
90101
// ========

clang/lib/Basic/Builtins.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,14 +313,22 @@ static void parseCommaSeparatedIndices(const char *CurrPos,
313313
assert(*EndPos == '>' && "Index list must end with '>'");
314314
}
315315

316-
bool Builtin::Context::isNonNull(unsigned ID,
317-
llvm::SmallVectorImpl<int> &Indxs) const {
316+
bool Builtin::Context::isNonNull(unsigned ID, llvm::SmallVectorImpl<int> &Indxs,
317+
Info::NonNullMode &Mode) const {
318318

319319
const char *AttrPos = ::strchr(getAttributesString(ID), 'N');
320320
if (!AttrPos)
321321
return false;
322322

323-
++AttrPos;
323+
AttrPos += 2; // skip 'N' and ':'
324+
if (*AttrPos == '0')
325+
Mode = Info::NonNullMode::NonOptimizing;
326+
else if (*AttrPos == '1')
327+
Mode = Info::NonNullMode::Optimizing;
328+
else
329+
llvm_unreachable("Unrecognized NonNull optimization mode");
330+
AttrPos += 2; // skip mode and ':'
331+
324332
parseCommaSeparatedIndices(AttrPos, Indxs);
325333

326334
return true;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17142,13 +17142,23 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
1714217142
}
1714317143

1714417144
SmallVector<int, 4> Indxs;
17145-
if (Context.BuiltinInfo.isNonNull(BuiltinID, Indxs) &&
17145+
Builtin::Info::NonNullMode OptMode;
17146+
if (Context.BuiltinInfo.isNonNull(BuiltinID, Indxs, OptMode) &&
1714617147
!FD->hasAttr<NonNullAttr>()) {
17147-
llvm::SmallVector<ParamIdx, 4> ParamIndxs;
17148-
for (int I : Indxs)
17149-
ParamIndxs.push_back(ParamIdx(I + 1, FD));
17150-
FD->addAttr(NonNullAttr::CreateImplicit(Context, ParamIndxs.data(),
17151-
ParamIndxs.size()));
17148+
if (OptMode == Builtin::Info::NonNullMode::NonOptimizing) {
17149+
for (int I : Indxs) {
17150+
ParmVarDecl *PVD = FD->getParamDecl(I);
17151+
QualType T = PVD->getType();
17152+
T = Context.getAttributedType(attr::TypeNonNull, T, T);
17153+
PVD->setType(T);
17154+
}
17155+
} else if (OptMode == Builtin::Info::NonNullMode::Optimizing) {
17156+
llvm::SmallVector<ParamIdx, 4> ParamIndxs;
17157+
for (int I : Indxs)
17158+
ParamIndxs.push_back(ParamIdx(I + 1, FD));
17159+
FD->addAttr(NonNullAttr::CreateImplicit(Context, ParamIndxs.data(),
17160+
ParamIndxs.size()));
17161+
}
1715217162
}
1715317163
if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
1715417164
!FD->hasAttr<ReturnsTwiceAttr>())

clang/test/Analysis/stream.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ void check_fputs(void) {
5252

5353
void check_fprintf(void) {
5454
FILE *fp = tmpfile();
55-
fprintf(fp, "ABC"); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
55+
fprintf(fp, "ABC"); // expected-warning {{Stream pointer might be NULL}}
5656
fclose(fp);
5757
}
5858

5959
void check_fscanf(void) {
6060
FILE *fp = tmpfile();
61-
fscanf(fp, "ABC"); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
61+
fscanf(fp, "ABC"); // expected-warning {{Stream pointer might be NULL}}
6262
fclose(fp);
6363
}
6464

@@ -152,13 +152,13 @@ void f_dopen(int fd) {
152152

153153
void f_vfprintf(int fd, va_list args) {
154154
FILE *F = fdopen(fd, "r");
155-
vfprintf(F, "%d", args); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
155+
vfprintf(F, "%d", args); // expected-warning {{Stream pointer might be NULL}}
156156
fclose(F);
157157
}
158158

159159
void f_vfscanf(int fd, va_list args) {
160160
FILE *F = fdopen(fd, "r");
161-
vfscanf(F, "%u", args); // expected-warning {{Null pointer passed to 1st parameter expecting 'nonnull'}}
161+
vfscanf(F, "%u", args); // expected-warning {{Stream pointer might be NULL}}
162162
fclose(F);
163163
}
164164

0 commit comments

Comments
 (0)