From: Eli Friedman Date: Sun, 3 May 2009 22:36:05 +0000 (+0000) Subject: PR2524: downgrade taking address of expression of type 'void' to an X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53202857c60214d80950a975e6e52aebf30bd16a;p=clang PR2524: downgrade taking address of expression of type 'void' to an extension warning. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70805 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 38d2124e64..441aae2c73 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -147,6 +147,9 @@ public: LV_MemberFunction }; isLvalueResult isLvalue(ASTContext &Ctx) const; + + // Same as above, but excluding checks for non-object and void types in C + isLvalueResult isLvalueInternal(ASTContext &Ctx) const; /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0e6ce3b072..1ea237eef5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1021,6 +1021,8 @@ def err_typecheck_sclass_func : Error<"illegal storage class on function">; def err_static_block_func : Error< "function declared in block scope cannot have 'static' storage class">; def err_typecheck_address_of : Error<"address of %0 requested">; +def ext_typecheck_addrof_void : Extension< + "ISO C forbids taking the address of an expression of type 'void'">; def err_typecheck_invalid_lvalue_addrof : Error< "address expression must be an lvalue or a function designator">; def err_typecheck_unary_expr : Error< diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 19d67bb7f8..13d2a1be3f 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -603,18 +603,26 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { /// - reference type [C++ [expr]] /// Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { + assert(!TR->isReferenceType() && "Expressions can't have reference type."); + + isLvalueResult Res = isLvalueInternal(Ctx); + if (Res != LV_Valid || Ctx.getLangOptions().CPlusPlus) + return Res; + // first, check the type (C99 6.3.2.1). Expressions with function // type in C are not lvalues, but they can be lvalues in C++. - if (!Ctx.getLangOptions().CPlusPlus && TR->isFunctionType()) + if (TR->isFunctionType()) return LV_NotObjectType; // Allow qualified void which is an incomplete type other than void (yuck). if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) return LV_IncompleteVoidType; - assert(!TR->isReferenceType() && "Expressions can't have reference type."); + return LV_Valid; +} - // the type looks fine, now check the expression +// Check whether the expression can be sanely treated like an l-value +Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { switch (getStmtClass()) { case StringLiteralClass: // C99 6.5.1p4 case ObjCEncodeExprClass: // @encode behaves like its string in every way. @@ -754,8 +762,6 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { return LV_Valid; case PredefinedExprClass: return LV_Valid; - case VAArgExprClass: - return LV_NotObjectType; case CXXDefaultArgExprClass: return cast(this)->getExpr()->isLvalue(Ctx); case CXXConditionDeclExprClass: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6ce98cd28f..36ec9c65c1 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4245,7 +4245,12 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator - if (!op->getType()->isFunctionType()) { + if (op->getType()->isFunctionType()) { + // Function designator is valid + } else if (lval == Expr::LV_IncompleteVoidType) { + Diag(OpLoc, diag::ext_typecheck_addrof_void) + << op->getSourceRange(); + } else { // FIXME: emit more specific diag... Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) << op->getSourceRange(); diff --git a/test/Sema/deref.c b/test/Sema/deref.c index fad56430a0..965940e26d 100644 --- a/test/Sema/deref.c +++ b/test/Sema/deref.c @@ -1,4 +1,5 @@ -// RUN: clang-cc -fsyntax-only -verify -std=c90 %s +/* RUN: clang-cc -fsyntax-only -verify -std=c90 -pedantic %s + */ void foo (void) { @@ -17,7 +18,7 @@ void foo2 (void) void foo3 (void) { void* x = 0; - void* y = &*x; // expected-error{{address expression must be an lvalue or a function designator}} + void* y = &*x; /* expected-warning{{address of an expression of type 'void'}} */ } extern const void cv1; @@ -30,7 +31,7 @@ const void *foo4 (void) extern void cv2; void *foo5 (void) { - return &cv2; // expected-error{{address expression must be an lvalue or a function designator}} + return &cv2; /* expected-warning{{address of an expression of type 'void'}} */ } typedef const void CVT; diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c index d5b4aac6f7..8d2f0b1fa8 100644 --- a/test/Sema/varargs.c +++ b/test/Sema/varargs.c @@ -56,7 +56,7 @@ void f7(int a, ...) { __builtin_va_list ap; __builtin_va_start(ap, a); // FIXME: This error message is sub-par. - __builtin_va_arg(ap, int) = 1; // expected-error {{non-object type 'int' is not assignable}} + __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}} __builtin_va_end(ap); }