From: Richard Smith Date: Sat, 2 Feb 2013 02:14:45 +0000 (+0000) Subject: PR15132: Replace "address expression must be an lvalue or a function X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3fa3feab35096b608f1d79bb541798b37a55e7b9;p=clang PR15132: Replace "address expression must be an lvalue or a function designator" diagnostic with more correct and more human-friendly "cannot take address of rvalue of type 'T'". For the case of & &T::f, provide a custom diagnostic, rather than unhelpfully saying "cannot take address of rvalue of type ''". For the case of &array_temporary, treat it just like a class temporary (including allowing it as an extension); the existing diagnostic wording for the class temporary case works fine. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174262 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3e3b816ce2..bcc33d1982 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4160,12 +4160,14 @@ def err_invalid_form_pointer_member_function : Error< "cannot create a non-constant pointer to member function">; def err_parens_pointer_member_function : Error< "cannot parenthesize the name of a method when forming a member pointer">; +def err_typecheck_invalid_lvalue_addrof_addrof_function : Error< + "extra '&' taking address of overloaded function">; def err_typecheck_invalid_lvalue_addrof : Error< - "address expression must be an lvalue or a function designator">; -def ext_typecheck_addrof_class_temporary : ExtWarn< + "cannot take the address of an rvalue of type %0">; +def ext_typecheck_addrof_temporary : ExtWarn< "taking the address of a temporary object of type %0">, InGroup>, DefaultError; -def err_typecheck_addrof_class_temporary : Error< +def err_typecheck_addrof_temporary : Error< "taking the address of a temporary object of type %0">; def err_typecheck_unary_expr : Error< "invalid argument type %0 to unary expression">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0465707e7c..ef852d354f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8033,7 +8033,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){ if (PTy->getKind() == BuiltinType::Overload) { if (!isa(OrigOp.get()->IgnoreParens())) { - S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + assert(cast(OrigOp.get()->IgnoreParens())->getOpcode() + == UO_AddrOf); + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function) << OrigOp.get()->getSourceRange(); return QualType(); } @@ -8077,10 +8079,10 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, Expr::LValueClassification lval = op->ClassifyLValue(S.Context); unsigned AddressOfError = AO_No_Error; - if (lval == Expr::LV_ClassTemporary) { + if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) { bool sfinae = S.isSFINAEContext(); - S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary - : diag::ext_typecheck_addrof_class_temporary) + S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_temporary + : diag::ext_typecheck_addrof_temporary) << op->getType() << op->getSourceRange(); if (sfinae) return QualType(); @@ -8128,9 +8130,8 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, if (isa(op)) { AddressOfError = AO_Property_Expansion; } else { - // FIXME: emit more specific diag... S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) - << op->getSourceRange(); + << op->getType() << op->getSourceRange(); return QualType(); } } diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp index 73bbca13b1..3144e941ef 100644 --- a/test/CodeGenCXX/cxx0x-initializer-array.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp @@ -53,6 +53,7 @@ namespace array_dtor { struct S { S(); ~S(); }; using T = S[3]; void f(const T &); + void f(T *); // CHECK: define void @_ZN10array_dtor1gEv( void g() { // CHECK: %[[ARRAY:.*]] = alloca [3 x @@ -68,10 +69,9 @@ namespace array_dtor { // Destruct loop. // CHECK: call void @_ZN10array_dtor1SD1Ev( // CHECK: br i1 + f(T{}); // CHECK: ret void - - f(T{}); } // CHECK: define void @_ZN10array_dtor1hEv( void h() { @@ -89,6 +89,23 @@ namespace array_dtor { // CHECK: call void @_ZN10array_dtor1SD1Ev( // CHECK: br i1 + // CHECK: ret void + } + // CHECK: define void @_ZN10array_dtor1iEv( + void i() { + // CHECK: %[[ARRAY:.*]] = alloca [3 x + // CHECK: br + + // CHECK: call void @_ZN10array_dtor1SC1Ev( + // CHECK: br i1 + + // CHECK: call void @_ZN10array_dtor1fEPA3_NS_1SE( + // CHECK: br + + // CHECK: call void @_ZN10array_dtor1SD1Ev( + // CHECK: br i1 + f(&T{}); + // CHECK: ret void } } diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm index 1eab15bee9..fb90b16a97 100644 --- a/test/Parser/objcxx0x-lambda-expressions.mm +++ b/test/Parser/objcxx0x-lambda-expressions.mm @@ -10,7 +10,7 @@ class C { []; // expected-error {{expected body of lambda expression}} [=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}} - [&this] {}; // expected-error {{address expression must be an lvalue}} + [&this] {}; // expected-error {{cannot take the address of an rvalue of type 'C *'}} [] {}; [=] (int i) {}; [&] (int) mutable -> void {}; diff --git a/test/Sema/complex-imag.c b/test/Sema/complex-imag.c index 1c6fb159bc..deaf627753 100644 --- a/test/Sema/complex-imag.c +++ b/test/Sema/complex-imag.c @@ -4,7 +4,7 @@ void f1() { int a = 1; int b = __imag a; int *c = &__real a; - int *d = &__imag a; // expected-error {{must be an lvalue}} + int *d = &__imag a; // expected-error {{cannot take the address of an rvalue of type 'int'}} } void f2() { @@ -18,7 +18,7 @@ void f3() { double a = 1; double b = __imag a; double *c = &__real a; - double *d = &__imag a; // expected-error {{must be an lvalue}} + double *d = &__imag a; // expected-error {{cannot take the address of an rvalue of type 'double'}} } void f4() { diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c index 2b8cfbfa68..32bd0dfdd5 100644 --- a/test/Sema/expr-address-of.c +++ b/test/Sema/expr-address-of.c @@ -90,8 +90,8 @@ void f5() { lvalue we would need to give a warning. Note that gcc warns about this as a register before it warns about it as an invalid lvalue. */ - int *_dummy0 = &(int*) arr; // expected-error {{address expression must be an lvalue or a function designator}} - int *_dummy1 = &(arr + 1); // expected-error {{address expression must be an lvalue or a function designator}} + int *_dummy0 = &(int*) arr; // expected-error {{cannot take the address of an rvalue}} + int *_dummy1 = &(arr + 1); // expected-error {{cannot take the address of an rvalue}} } void f6(register int x) { @@ -109,12 +109,12 @@ char* f7() { } void f8() { - void *dummy0 = &f8(); // expected-error {{address expression must be an lvalue or a function designator}} + void *dummy0 = &f8(); // expected-error {{cannot take the address of an rvalue of type 'void'}} extern void v; - void *dummy1 = &(1 ? v : f8()); // expected-error {{address expression must be an lvalue or a function designator}} + void *dummy1 = &(1 ? v : f8()); // expected-error {{cannot take the address of an rvalue of type 'void'}} - void *dummy2 = &(f8(), v); // expected-error {{address expression must be an lvalue or a function designator}} + void *dummy2 = &(f8(), v); // expected-error {{cannot take the address of an rvalue of type 'void'}} - void *dummy3 = &({ ; }); // expected-error {{address expression must be an lvalue or a function designator}} + void *dummy3 = &({ ; }); // expected-error {{cannot take the address of an rvalue of type 'void'}} } diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c index 07081edd1d..663d3d5947 100644 --- a/test/Sema/varargs.c +++ b/test/Sema/varargs.c @@ -57,7 +57,7 @@ void f7(int a, ...) { __builtin_va_start(ap, a); // FIXME: This error message is sub-par. __builtin_va_arg(ap, int) = 1; // expected-error {{expression is not assignable}} - int *x = &__builtin_va_arg(ap, int); // expected-error {{address expression must be an lvalue or a function designator}} + int *x = &__builtin_va_arg(ap, int); // expected-error {{cannot take the address of an rvalue}} __builtin_va_end(ap); } diff --git a/test/SemaCXX/address-of.cpp b/test/SemaCXX/address-of.cpp index 677dc8966b..373e44c17e 100644 --- a/test/SemaCXX/address-of.cpp +++ b/test/SemaCXX/address-of.cpp @@ -22,12 +22,12 @@ enum E { }; void test() { - (void)&Enumerator; // expected-error{{address expression must be an lvalue or a function designator}} + (void)&Enumerator; // expected-error{{cannot take the address of an rvalue of type 'E'}} } template void test2() { - (void)&N; // expected-error{{address expression must be an lvalue or a function designator}} + (void)&N; // expected-error{{cannot take the address of an rvalue of type 'int'}} } // PR clang/3222 @@ -41,7 +41,7 @@ struct PR11066 { }; void PR11066::test() { - int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{address expression must be an lvalue or a function designator}} + int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{extra '&' taking address of overloaded function}} } namespace test3 { diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index 7595f1dfa1..692aaefc9d 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -146,7 +146,7 @@ void test() (void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}} (void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}} // By the way, this isn't an lvalue: - &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}} + &(i1 ? i1 : i2); // expected-error {{cannot take the address of an rvalue}} // p4 (lvalue, same type) Fields flds; @@ -183,7 +183,7 @@ void test() i1 ? &MixedFields::ci : &MixedFields::cvi; (void)(i1 ? &MixedFields::ci : &MixedFields::vi); // Conversion of primitives does not result in an lvalue. - &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}} + &(i1 ? i1 : d1); // expected-error {{cannot take the address of an rvalue}} (void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}} (void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}} diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp index 7d1fa7e3ec..f53ac6dff9 100644 --- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp +++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp @@ -125,3 +125,8 @@ namespace multidimensional_array { g({{1,2},{3,4}}); } } + +namespace array_addressof { + using T = int[5]; + T *p = &T{1,2,3,4,5}; // expected-error {{taking the address of a temporary object of type 'T' (aka 'int [5]')}} +} diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp index d148f76698..b49f63b980 100644 --- a/test/SemaCXX/nullptr.cpp +++ b/test/SemaCXX/nullptr.cpp @@ -57,7 +57,7 @@ nullptr_t f(nullptr_t null) o2(nullptr); // expected-error {{ambiguous}} // nullptr is an rvalue, null is an lvalue - (void)&nullptr; // expected-error {{address expression must be an lvalue}} + (void)&nullptr; // expected-error {{cannot take the address of an rvalue of type 'nullptr_t'}} nullptr_t *pn = &null; // You can reinterpret_cast nullptr to an integer. diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 59da9c667e..434054ecbd 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -328,7 +328,7 @@ namespace rdar13000548 { template struct X { typedef R (*fptype)(int); - static fptype f() { return &F; } // expected-error{{address expression must be an lvalue or a function designator}} + static fptype f() { return &F; } // expected-error{{cannot take the address of an rvalue of type 'int (*)(int)'}} }; int g(int);