Add returns_twice to functions that are known to return twice. This implements
the same behavior of gcc by keeping the attribute out of the function type.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141803 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 60bcde3..d3a5eaf 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -77,6 +77,7 @@
// in that it accepts its arguments as a va_list rather than
// through an ellipsis
// e -> const, but only when -fmath-errno=0
+// j -> returns_twice (like setjmp)
// FIXME: gcc has nonnull
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -427,7 +428,7 @@
BUILTIN(__builtin_extract_return_addr, "v*v*", "n")
BUILTIN(__builtin_frame_address, "v*IUi", "n")
BUILTIN(__builtin_flt_rounds, "i", "nc")
-BUILTIN(__builtin_setjmp, "iv**", "")
+BUILTIN(__builtin_setjmp, "iv**", "j")
BUILTIN(__builtin_longjmp, "vv**i", "r")
BUILTIN(__builtin_unwind_init, "v", "")
BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc")
@@ -672,6 +673,17 @@
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES)
// POSIX setjmp.h
+
+LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(__sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(vfork, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(getcontext, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES)
// non-standard but very common
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index fbf4ef4..5afa020 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -103,6 +103,11 @@
return strchr(GetRecord(ID).Attributes, 'r') != 0;
}
+ /// isReturnsTwice - Return true if we know this builtin can return twice.
+ bool isReturnsTwice(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'j') != 0;
+ }
+
/// isLibFunction - Return true if this is a builtin for a libc/libm function,
/// with a "__builtin_" prefix (e.g. __builtin_abs).
bool isLibFunction(unsigned ID) const {
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 73f5cdb..4f3e8ad 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -468,6 +468,10 @@
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
+
+ if (D->hasAttr<ReturnsTwiceAttr>())
+ Proto += " __attribute((returns_twice))";
+
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index f52abef..6ae2d0c 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -729,6 +729,8 @@
// FIXME: handle sseregparm someday...
if (TargetDecl) {
+ if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
+ FuncAttrs |= llvm::Attribute::ReturnsTwice;
if (TargetDecl->hasAttr<NoThrowAttr>())
FuncAttrs |= llvm::Attribute::NoUnwind;
else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d19023d..8e2ff5c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -7263,6 +7263,9 @@
FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context));
}
+ if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) &&
+ !FD->getAttr<ReturnsTwiceAttr>())
+ FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context));
if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr<NoThrowAttr>())
FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context));
if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr<ConstAttr>())
diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m
index a04401b..6fb5b3c 100644
--- a/test/Analysis/security-syntax-checks.m
+++ b/test/Analysis/security-syntax-checks.m
@@ -170,7 +170,7 @@
//===----------------------------------------------------------------------===
typedef int __int32_t;
typedef __int32_t pid_t;
-pid_t vfork(void);
+pid_t vfork(void); //expected-warning{{declaration of built-in function 'vfork' requires inclusion of the header <setjmp.h>}}
void test_vfork() {
vfork(); //expected-warning{{Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process.}}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index fd98458..6cbf40b 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -100,3 +100,14 @@
__attribute__ ((returns_twice)) void f18(void) {
f17();
}
+
+// CHECK: define void @f19()
+// CHECK: {
+// CHECK: call i32 @setjmp(i32* null)
+// CHECK: returns_twice
+// CHECK: ret void
+typedef int jmp_buf[((9 * 2) + 3 + 16)];
+int setjmp(jmp_buf);
+void f19(void) {
+ setjmp(0);
+}
diff --git a/test/Sema/attr-returns-twice.c b/test/Sema/attr-returns-twice.c
new file mode 100644
index 0000000..13f53e3
--- /dev/null
+++ b/test/Sema/attr-returns-twice.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+int a __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}
+
+__attribute__((returns_twice)) void t0(void) {
+}
+
+void t1() __attribute__((returns_twice));
+
+void t2() __attribute__((returns_twice(2))); // expected-error {{attribute takes no arguments}}
+
+typedef void (*t3)(void) __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}