mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-25 14:28:54 -04:00

ExprWithCleanups wraps full-expressions that require temporary destructors and highlights the moment of time in which these destructors need to be called (i.e., "at the end of the full-expression..."). Such expressions don't necessarily return an object; they may return anything, including a null or undefined value. When the analyzer tries to understand where the null or undefined value came from in order to present better diagnostics to the user, it will now skip any ExprWithCleanups it encounters and look into the expression itself. Differential Revision: https://reviews.llvm.org/D48204 llvm-svn: 335559
104 lines
1.8 KiB
C++
104 lines
1.8 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
|
|
// expected-no-diagnostics
|
|
|
|
extern void __assert_fail (__const char *__assertion, __const char *__file,
|
|
unsigned int __line, __const char *__function)
|
|
__attribute__ ((__noreturn__));
|
|
#define assert(expr) \
|
|
((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
|
|
|
|
class ButterFly {
|
|
private:
|
|
ButterFly() { }
|
|
public:
|
|
int triggerderef() {
|
|
return 0;
|
|
}
|
|
};
|
|
ButterFly *getInP();
|
|
class X{
|
|
ButterFly *p;
|
|
void setP(ButterFly *inP) {
|
|
if(inP)
|
|
;
|
|
p = inP;
|
|
};
|
|
void subtest1() {
|
|
ButterFly *inP = getInP();
|
|
setP(inP);
|
|
}
|
|
int subtest2() {
|
|
int c = p->triggerderef(); // no-warning
|
|
return c;
|
|
}
|
|
int test() {
|
|
subtest1();
|
|
return subtest2();
|
|
}
|
|
};
|
|
|
|
typedef const int *Ty;
|
|
extern
|
|
Ty notNullArg(Ty cf) __attribute__((nonnull));
|
|
typedef const void *CFTypeRef;
|
|
extern Ty getTyVal();
|
|
inline void radar13224271_callee(Ty def, Ty& result ) {
|
|
result = def;
|
|
// Clearly indicates that result cannot be 0 if def is not NULL.
|
|
assert( (result != 0) || (def == 0) );
|
|
}
|
|
void radar13224271_caller()
|
|
{
|
|
Ty value;
|
|
radar13224271_callee(getTyVal(), value );
|
|
notNullArg(value); // no-warning
|
|
}
|
|
|
|
struct Foo {
|
|
int *ptr;
|
|
Foo(int *p) {
|
|
*p = 1; // no-warning
|
|
}
|
|
};
|
|
void idc(int *p3) {
|
|
if (p3)
|
|
;
|
|
}
|
|
int *retNull() {
|
|
return 0;
|
|
}
|
|
void test(int *p1, int *p2) {
|
|
idc(p1);
|
|
Foo f(p1);
|
|
}
|
|
|
|
struct Bar {
|
|
int x;
|
|
};
|
|
void idcBar(Bar *b) {
|
|
if (b)
|
|
;
|
|
}
|
|
void testRefToField(Bar *b) {
|
|
idcBar(b);
|
|
int &x = b->x; // no-warning
|
|
x = 5;
|
|
}
|
|
|
|
namespace get_deref_expr_with_cleanups {
|
|
struct S {
|
|
~S();
|
|
};
|
|
S *conjure();
|
|
// The argument won't be used, but it'll cause cleanups
|
|
// to appear around the call site.
|
|
S *get_conjured(S _) {
|
|
S *s = conjure();
|
|
if (s) {}
|
|
return s;
|
|
}
|
|
void test_conjured() {
|
|
S &s = *get_conjured(S()); // no-warning
|
|
}
|
|
} // namespace get_deref_expr_with_cleanups
|