Fix bugs checking va_start in lambdas and erroneous contexts
Summary:
First, getCurFunction looks through blocks and lambdas, which is wrong.
Inside a lambda, va_start should refer to the lambda call operator
prototype. This fixes PR32737.
Second, we shouldn't use any of the getCur* methods, because they look
through contexts that we don't want to look through (EnumDecl,
CapturedStmtDecl). We can use CurContext directly as the calling
context.
Finally, this code assumed that CallExprs would never appear outside of
code contexts (block, function, obj-c method), which is wrong. Struct
member initializers are an easy way to create and parse exprs in a
non-code context.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D32761
llvm-svn: 302188
2017-05-05 03:51:05 +08:00
|
|
|
// RUN: %clang_cc1 -std=c++03 -verify %s
|
|
|
|
// RUN: %clang_cc1 -std=c++11 -verify %s
|
|
|
|
|
|
|
|
__builtin_va_list ap;
|
2016-04-24 21:30:21 +08:00
|
|
|
|
|
|
|
class string;
|
|
|
|
void f(const string& s, ...) { // expected-note {{parameter of type 'const string &' is declared here}}
|
|
|
|
__builtin_va_start(ap, s); // expected-warning {{passing an object of reference type to 'va_start' has undefined behavior}}
|
|
|
|
}
|
|
|
|
|
2017-11-02 07:38:37 +08:00
|
|
|
void g(register int i, ...) { // expected-warning 0-1{{deprecated}}
|
Fix bugs checking va_start in lambdas and erroneous contexts
Summary:
First, getCurFunction looks through blocks and lambdas, which is wrong.
Inside a lambda, va_start should refer to the lambda call operator
prototype. This fixes PR32737.
Second, we shouldn't use any of the getCur* methods, because they look
through contexts that we don't want to look through (EnumDecl,
CapturedStmtDecl). We can use CurContext directly as the calling
context.
Finally, this code assumed that CallExprs would never appear outside of
code contexts (block, function, obj-c method), which is wrong. Struct
member initializers are an easy way to create and parse exprs in a
non-code context.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D32761
llvm-svn: 302188
2017-05-05 03:51:05 +08:00
|
|
|
__builtin_va_start(ap, i); // UB in C, OK in C++
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't crash when there is no last parameter.
|
|
|
|
void no_params(...) {
|
|
|
|
int a;
|
|
|
|
__builtin_va_start(ap, a); // expected-warning {{second argument to 'va_start' is not the last named parameter}}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reject this. The __builtin_va_start would execute in Foo's non-variadic
|
|
|
|
// default ctor.
|
|
|
|
void record_context(int a, ...) {
|
|
|
|
struct Foo {
|
2020-03-26 23:07:50 +08:00
|
|
|
// expected-error@+1 {{'va_start' cannot be used outside a function}}
|
Fix bugs checking va_start in lambdas and erroneous contexts
Summary:
First, getCurFunction looks through blocks and lambdas, which is wrong.
Inside a lambda, va_start should refer to the lambda call operator
prototype. This fixes PR32737.
Second, we shouldn't use any of the getCur* methods, because they look
through contexts that we don't want to look through (EnumDecl,
CapturedStmtDecl). We can use CurContext directly as the calling
context.
Finally, this code assumed that CallExprs would never appear outside of
code contexts (block, function, obj-c method), which is wrong. Struct
member initializers are an easy way to create and parse exprs in a
non-code context.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D32761
llvm-svn: 302188
2017-05-05 03:51:05 +08:00
|
|
|
void meth(int a, int b = (__builtin_va_start(ap, a), 0)) {}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#if __cplusplus >= 201103L
|
|
|
|
// We used to have bugs identifying the correct enclosing function scope in a
|
|
|
|
// lambda.
|
|
|
|
|
|
|
|
void fixed_lambda_varargs_function(int a, ...) {
|
|
|
|
[](int b) {
|
|
|
|
__builtin_va_start(ap, b); // expected-error {{'va_start' used in function with fixed args}}
|
|
|
|
}(42);
|
|
|
|
}
|
|
|
|
void varargs_lambda_fixed_function(int a) {
|
|
|
|
[](int b, ...) {
|
|
|
|
__builtin_va_start(ap, b); // correct
|
|
|
|
}(42);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto fixed_lambda_global = [](int f) {
|
|
|
|
__builtin_va_start(ap, f); // expected-error {{'va_start' used in function with fixed args}}
|
|
|
|
};
|
|
|
|
auto varargs_lambda_global = [](int f, ...) {
|
|
|
|
__builtin_va_start(ap, f); // correct
|
|
|
|
};
|
|
|
|
|
|
|
|
void record_member_init(int a, ...) {
|
|
|
|
struct Foo {
|
|
|
|
int a = 0;
|
|
|
|
// expected-error@+1 {{'va_start' cannot be used outside a function}}
|
|
|
|
int b = (__builtin_va_start(ap, a), 0);
|
|
|
|
};
|
2016-04-24 21:30:21 +08:00
|
|
|
}
|
Fix bugs checking va_start in lambdas and erroneous contexts
Summary:
First, getCurFunction looks through blocks and lambdas, which is wrong.
Inside a lambda, va_start should refer to the lambda call operator
prototype. This fixes PR32737.
Second, we shouldn't use any of the getCur* methods, because they look
through contexts that we don't want to look through (EnumDecl,
CapturedStmtDecl). We can use CurContext directly as the calling
context.
Finally, this code assumed that CallExprs would never appear outside of
code contexts (block, function, obj-c method), which is wrong. Struct
member initializers are an easy way to create and parse exprs in a
non-code context.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D32761
llvm-svn: 302188
2017-05-05 03:51:05 +08:00
|
|
|
#endif
|