/// arguments to the builtin that are required to be integer constant
/// expressions.
QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error,
- unsigned *IntegerConstantArgs = nullptr,
- bool *OverrideNonnullReturn = nullptr,
- unsigned *OverrideNonnullArgs = nullptr) const;
+ unsigned *IntegerConstantArgs = nullptr) const;
private:
CanQualType getFromTargetType(unsigned Type) const;
// S -> signed
// U -> unsigned
// I -> Required to constant fold to an integer constant expression.
-// N -> Do not assume non-null for optimizations even if attributed nonnull.
-// This can be used when a relevant standard requires arguments or
-// returns to be non-null and they are attributed accordingly but in
-// practice are not used in this way. This typically used when a size
-// parameter is also provided and when zero it would be reasonable to
-// give an invalid pointer.
//
// Types may be postfixed with the following modifiers:
// * -> pointer (optionally followed by an address space number, if no address
LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES)
LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES)
// C99 string.h
-LIBBUILTIN(memcpy, "Nv*Nv*NvC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(memcmp, "iNvC*NvC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(memmove, "Nv*Nv*NvC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strncpy, "Nc*Nc*NcC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strncmp, "iNcC*NcC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strncat, "c*c*NcC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(memchr, "Nv*NvC*iz", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(memset, "Nv*Nv*iz", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES)
-LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strncmp, "icC*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES)
+LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES)
// C99 stdio.h
LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES)
// C99 wchar.h
// FIXME: This list is incomplete. We should cover at least the functions that
// take format strings.
-LIBBUILTIN(wcschr, "w*wC*w", "f", "wchar.h", ALL_LANGUAGES)
-LIBBUILTIN(wcscmp, "iwC*wC*", "f", "wchar.h", ALL_LANGUAGES)
-LIBBUILTIN(wcslen, "zwC*", "f", "wchar.h", ALL_LANGUAGES)
-LIBBUILTIN(wcsncmp, "iNwC*NwC*z", "f", "wchar.h", ALL_LANGUAGES)
-LIBBUILTIN(wmemchr, "Nw*NwC*wz", "f", "wchar.h", ALL_LANGUAGES)
-LIBBUILTIN(wmemcmp, "iNwC*NwC*z", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wcschr, "w*wC*w", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wcscmp, "iwC*wC*", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wcslen, "zwC*", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wcsncmp, "iwC*wC*z", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wmemchr, "w*wC*wz", "f", "wchar.h", ALL_LANGUAGES)
+LIBBUILTIN(wmemcmp, "iwC*wC*z", "f", "wchar.h", ALL_LANGUAGES)
// C99
// In some systems setjmp is a macro that expands to _setjmp. We undefine
/// to be an Integer Constant Expression.
static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
ASTContext::GetBuiltinTypeError &Error,
- bool &RequiresICE, bool &OverrideNonnull,
+ bool &RequiresICE,
bool AllowTypeModifiers) {
// Modifiers.
int HowLong = 0;
bool Signed = false, Unsigned = false;
RequiresICE = false;
- OverrideNonnull = false;
-
+
// Read the prefixed modifiers first.
bool Done = false;
while (!Done) {
case 'I':
RequiresICE = true;
break;
- case 'N':
- OverrideNonnull = true;
- break;
case 'S':
assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
assert(!Signed && "Can't use 'S' modifier multiple times!");
assert(End != Str && "Missing vector size");
Str = End;
- QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE,
- OverrideNonnull, false);
+ QualType ElementType = DecodeTypeFromStr(Str, Context, Error,
+ RequiresICE, false);
assert(!RequiresICE && "Can't require vector ICE");
// TODO: No way to make AltiVec vectors in builtins yet.
assert(End != Str && "Missing vector size");
Str = End;
-
+
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE,
- OverrideNonnull, false);
+ false);
Type = Context.getExtVectorType(ElementType, NumElements);
break;
}
case 'X': {
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE,
- OverrideNonnull, false);
+ false);
assert(!RequiresICE && "Can't require complex ICE");
Type = Context.getComplexType(ElementType);
break;
}
/// GetBuiltinType - Return the type for the specified builtin.
-QualType ASTContext::GetBuiltinType(unsigned Id, GetBuiltinTypeError &Error,
- unsigned *IntegerConstantArgs,
- bool *OverrideNonnullReturn,
- unsigned *OverrideNonnullArgs) const {
+QualType ASTContext::GetBuiltinType(unsigned Id,
+ GetBuiltinTypeError &Error,
+ unsigned *IntegerConstantArgs) const {
const char *TypeStr = BuiltinInfo.getTypeString(Id);
SmallVector<QualType, 8> ArgTypes;
bool RequiresICE = false;
- bool OverrideNonnull = false;
Error = GE_None;
- QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE,
- OverrideNonnull, true);
+ QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error,
+ RequiresICE, true);
if (Error != GE_None)
return QualType();
-
- if (OverrideNonnullReturn)
- *OverrideNonnullReturn = OverrideNonnull;
+
assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE");
-
+
while (TypeStr[0] && TypeStr[0] != '.') {
- QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE,
- OverrideNonnull, true);
+ QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true);
if (Error != GE_None)
return QualType();
- // If this argument should have any nonnull annotations overriden, fill in
- // the bitmask.
- if (OverrideNonnull && OverrideNonnullArgs)
- *OverrideNonnullArgs |= 1 << ArgTypes.size();
-
// If this argument is required to be an IntegerConstantExpression and the
// caller cares, fill in the bitmask we return.
if (RequiresICE && IntegerConstantArgs)
F.addAttributes(llvm::AttributeList::FunctionIndex, AS);
}
-/// Returns the attribute (either parameter attribute, or function
-/// attribute), which declares argument ArgNo to be non-null.
-static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD,
- QualType ArgType, unsigned ArgNo) {
- // FIXME: __attribute__((nonnull)) can also be applied to:
- // - references to pointers, where the pointee is known to be
- // nonnull (apparently a Clang extension)
- // - transparent unions containing pointers
- // In the former case, LLVM IR cannot represent the constraint. In
- // the latter case, we have no guarantee that the transparent union
- // is in fact passed as a pointer.
- if (!ArgType->isAnyPointerType() && !ArgType->isBlockPointerType())
- return nullptr;
- // First, check attribute on parameter itself.
- if (PVD) {
- if (auto ParmNNAttr = PVD->getAttr<NonNullAttr>())
- return ParmNNAttr;
- }
- // Check function attributes.
- if (!FD)
- return nullptr;
- for (const auto *NNAttr : FD->specific_attrs<NonNullAttr>()) {
- if (NNAttr->isNonNull(ArgNo))
- return NNAttr;
- }
- return nullptr;
-}
-
void CodeGenModule::ConstructAttributeList(
StringRef Name, const CGFunctionInfo &FI, CGCalleeInfo CalleeInfo,
AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite) {
CalleeInfo.getCalleeFunctionProtoType());
const Decl *TargetDecl = CalleeInfo.getCalleeDecl();
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
-
- // Check if this is a builtin function that might override some attributes.
- unsigned BuiltinID = FD ? FD->getBuiltinID() : 0;
- bool OverrideNonnullReturn = false;
- unsigned OverrideNonnullArgs = 0;
- if (BuiltinID) {
- ASTContext::GetBuiltinTypeError Error;
- getContext().GetBuiltinType(BuiltinID, Error, nullptr,
- &OverrideNonnullReturn, &OverrideNonnullArgs);
- // Note that we can't check the 'Error' here as there may be errors that
- // have been diagnosed and reported to the programmer as warnings but
- // repaired in the AST such as for implicit declarations of builtin
- // functions. None of those impact our usage of this to analyze attributes
- // for the builtins.
- }
bool HasOptnone = false;
// FIXME: handle sseregparm someday...
if (TargetDecl->hasAttr<ConvergentAttr>())
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
- if (FD) {
+ if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
AddAttributesFromFunctionProtoType(
- getContext(), FuncAttrs, FD->getType()->getAs<FunctionProtoType>());
+ getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>());
// Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
// These attributes are not inherited by overloads.
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- if (FD->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
+ if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
}
}
if (TargetDecl->hasAttr<RestrictAttr>())
RetAttrs.addAttribute(llvm::Attribute::NoAlias);
- if (TargetDecl->hasAttr<ReturnsNonNullAttr>() && !OverrideNonnullReturn)
+ if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
RetAttrs.addAttribute(llvm::Attribute::NonNull);
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
// we have a decl for the function and it has a target attribute then
// parse that and add it to the feature set.
StringRef TargetCPU = getTarget().getTargetOpts().CPU;
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
if (FD && FD->hasAttr<TargetAttr>()) {
llvm::StringMap<bool> FeatureMap;
getFunctionFeatureMap(FeatureMap, FD);
continue;
}
- if (FD && ArgNo < FD->param_size() && ParamType->isPointerType()) {
- auto *PVD = FD->getParamDecl(ArgNo);
- if (getNonNullAttr(FD, PVD, ParamType, PVD->getFunctionScopeIndex()) &&
- (!BuiltinID || (OverrideNonnullArgs & (1 << ArgNo)) == 0))
- Attrs.addAttribute(llvm::Attribute::NonNull);
- }
-
if (const auto *RefTy = ParamType->getAs<ReferenceType>()) {
QualType PTy = RefTy->getPointeeType();
if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote");
}
+/// Returns the attribute (either parameter attribute, or function
+/// attribute), which declares argument ArgNo to be non-null.
+static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD,
+ QualType ArgType, unsigned ArgNo) {
+ // FIXME: __attribute__((nonnull)) can also be applied to:
+ // - references to pointers, where the pointee is known to be
+ // nonnull (apparently a Clang extension)
+ // - transparent unions containing pointers
+ // In the former case, LLVM IR cannot represent the constraint. In
+ // the latter case, we have no guarantee that the transparent union
+ // is in fact passed as a pointer.
+ if (!ArgType->isAnyPointerType() && !ArgType->isBlockPointerType())
+ return nullptr;
+ // First, check attribute on parameter itself.
+ if (PVD) {
+ if (auto ParmNNAttr = PVD->getAttr<NonNullAttr>())
+ return ParmNNAttr;
+ }
+ // Check function attributes.
+ if (!FD)
+ return nullptr;
+ for (const auto *NNAttr : FD->specific_attrs<NonNullAttr>()) {
+ if (NNAttr->isNonNull(ArgNo))
+ return NNAttr;
+ }
+ return nullptr;
+}
+
namespace {
struct CopyBackSwiftError final : EHScopeStack::Cleanup {
Address Temp;
_setjmp(0);
}
-// Bogus declarations that will end up with bad types when detecting builtins,
-// but that we will still process when considering whether to add attributes.
-struct __jmp_buf_tag;
-extern int __sigsetjmp(struct __jmp_buf_tag *__env, int __savemask);
-
-// CHECK-LABEL: define void @f21()
-// CHECK: {
-// CHECK: call i32 @__sigsetjmp(%{{.*}}* null, i32 0)
-// CHECK: [[RT_CALL]]
-// CHECK: ret void
-void f21(void) {
- __sigsetjmp(0, 0);
-}
-
// CHECK: attributes [[NUW]] = { nounwind optsize{{.*}} }
// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize{{.*}} }
// CHECK: attributes [[NUW_OS_RN]] = { nounwind optsize readnone{{.*}} }
// CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b)
void bar8(int *a, int *b) __attribute__((nonnull))
__attribute__((nonnull(1))) {}
-
-// CHECK: declare void @foo_decl(i32* nonnull)
-void foo_decl(int *__attribute__((nonnull)));
-
-// CHECK: declare void @bar_decl(i32* nonnull)
-void bar_decl(int *) __attribute__((nonnull(1)));
-
-// CHECK: declare void @bar2_decl(i32*, i32* nonnull)
-void bar2_decl(int *, int *) __attribute__((nonnull(2)));
-
-// CHECK: declare nonnull i32* @bar3_decl()
-int *bar3_decl(void) __attribute__((returns_nonnull));
-
-// CHECK: declare i32 @bar4_decl(i32, i32* nonnull)
-int bar4_decl(int, int *) __attribute__((nonnull));
-
-// CHECK: declare i32 @bar5_decl(i32, i32* nonnull)
-int bar5_decl(int, int *) __attribute__((nonnull(1, 2)));
-
-// CHECK: declare i32 @bar6_decl(i64)
-int bar6_decl(TransparentUnion) __attribute__((nonnull(1)));
-
-// CHECK: declare void @bar7_decl(i32* nonnull, i32* nonnull)
-void bar7_decl(int *, int *)
- __attribute__((nonnull(1))) __attribute__((nonnull(2)));
-
-// CHECK: declare void @bar8_decl(i32* nonnull, i32* nonnull)
-void bar8_decl(int *, int *)
- __attribute__((nonnull)) __attribute__((nonnull(1)));
-
-// Clang specially disables nonnull attributes on some library builtin
-// functions to work around the fact that the standard and some vendors mark
-// them as nonnull even though they are frequently called in practice with null
-// arguments if a corresponding size argument is zero.
-
-// CHECK: declare i8* @memcpy(i8*, i8*, i64)
-void *memcpy(void *, const void *, unsigned long)
- __attribute__((nonnull(1, 2))) __attribute__((returns_nonnull));
-
-// CHECK: declare i32 @memcmp(i8*, i8*, i64)
-int memcmp(const void *, const void *, unsigned long) __attribute__((nonnull(1, 2)));
-
-// CHECK: declare i8* @memmove(i8*, i8*, i64)
-void *memmove(void *, const void *, unsigned long)
- __attribute__((nonnull(1, 2))) __attribute__((returns_nonnull));
-
-// CHECK: declare i8* @strncpy(i8*, i8*, i64)
-char *strncpy(char *, const char *, unsigned long)
- __attribute__((nonnull(1, 2))) __attribute__((returns_nonnull));
-
-// CHECK: declare i32 @strncmp(i8*, i8*, i64)
-int strncmp(const char *, const char *, unsigned long) __attribute__((nonnull(1, 2)));
-
-// CHECK: declare nonnull i8* @strncat(i8* nonnull, i8*, i64)
-char *strncat(char *, const char *, unsigned long)
- __attribute__((nonnull(1, 2))) __attribute__((returns_nonnull));
-
-// CHECK: declare i8* @memchr(i8*, i32, i64)
-void *memchr(const void *__attribute__((nonnull)), int, unsigned long)
- __attribute__((returns_nonnull));
-
-// CHECK: declare i8* @memset(i8*, i32, i64)
-void *memset(void *__attribute__((nonnull)), int, unsigned long)
- __attribute__((returns_nonnull));
-
-void use_declarations(int *p, void *volatile *sink) {
- foo_decl(p);
- bar_decl(p);
- bar2_decl(p, p);
- (void)bar3_decl();
- bar4_decl(42, p);
- bar5_decl(42, p);
- bar6_decl(p);
- bar7_decl(p, p);
- bar8_decl(p, p);
- *sink = (void *)&memcpy;
- *sink = (void *)&memcmp;
- *sink = (void *)&memmove;
- *sink = (void *)&strncpy;
- *sink = (void *)&strncmp;
- *sink = (void *)&strncat;
- *sink = (void *)&memchr;
- *sink = (void *)&memset;
-}