From: Steve Naroff Date: Sun, 13 Jan 2008 17:10:08 +0000 (+0000) Subject: Change Sema::CheckAddressOfOperation() to respect C99-only addressof rules. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08f196716775e3b5a5406b588f5f01a0169a8a5b;p=clang Change Sema::CheckAddressOfOperation() to respect C99-only addressof rules. Remove diagnostics from Sema::CheckIndirectionOperand(). C89/C99 allow dereferencing an incomplete type. clang appears to be emulating some incorrect gcc behavior (see below). void foo (void) { struct b; struct b* x = 0; struct b* y = &*x; // gcc produces an error ("dereferencing pointer to incomplete type") } With this patch, the above is now allowed. Bug/Patch by Eli Friedman! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45933 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 73c1687d11..ced6953c7d 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1618,6 +1618,17 @@ static Decl *getPrimaryDeclaration(Expr *e) { /// Note: The usual conversions are *not* applied to the operand of the & /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { + if (getLangOptions().C99) { + // Implement C99-only parts of addressof rules. + if (UnaryOperator* uOp = dyn_cast(op)) { + if (uOp->getOpcode() == UnaryOperator::Deref) + // Per C99 6.5.3.2, the address of a deref always returns a valid result + // (assuming the deref expression is valid). + return uOp->getSubExpr()->getType(); + } + // Technically, there should be a check for array subscript + // expressions here, but the result of one is always an lvalue anyway. + } Decl *dcl = getPrimaryDeclaration(op); Expr::isLvalueResult lval = op->isLvalue(); @@ -1651,19 +1662,12 @@ QualType Sema::CheckIndirectionOperand(Expr *op, SourceLocation OpLoc) { QualType qType = op->getType(); if (const PointerType *PT = qType->getAsPointerType()) { - QualType ptype = PT->getPointeeType(); - // C99 6.5.3.2p4. "if it points to an object,...". - if (ptype->isIncompleteType()) { // An incomplete type is not an object - // GCC compat: special case 'void *' (treat as extension, not error). - if (ptype->isVoidType()) { - Diag(OpLoc, diag::ext_typecheck_deref_ptr_to_void,op->getSourceRange()); - } else { - Diag(OpLoc, diag::err_typecheck_deref_incomplete_type, - ptype.getAsString(), op->getSourceRange()); - return QualType(); - } - } - return ptype; + // Note that per both C89 and C99, this is always legal, even + // if ptype is an incomplete type or void. + // It would be possible to warn about dereferencing a + // void pointer, but it's completely well-defined, + // and such a warning is unlikely to catch any mistakes. + return PT->getPointeeType(); } Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer, qType.getAsString(), op->getSourceRange()); diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 90a900a734..ea6da368cd 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -756,10 +756,6 @@ DIAG(err_typecheck_unary_expr, ERROR, "invalid argument type to unary expression '%0'") DIAG(err_typecheck_indirection_requires_pointer, ERROR, "indirection requires pointer operand ('%0' invalid)") -DIAG(err_typecheck_deref_incomplete_type, ERROR, - "dereferencing pointer to incomplete type '%0'") -DIAG(ext_typecheck_deref_ptr_to_void, WARNING, - "dereferencing void pointer") DIAG(err_typecheck_invalid_operands, ERROR, "invalid operands to binary expression ('%0' and '%1')") DIAG(err_typecheck_sub_ptr_object, ERROR, diff --git a/test/Sema/conditional-expr.c b/test/Sema/conditional-expr.c index f6b9d1f42d..87fe2d2ed6 100644 --- a/test/Sema/conditional-expr.c +++ b/test/Sema/conditional-expr.c @@ -1,7 +1,7 @@ // RUN: clang -fsyntax-only -verify -pedantic %s void foo() { *(0 ? (double *)0 : (void *)0) = 0; - *((void *) 0) = 0; // -expected-warning {{dereferencing void pointer}} -expected-error {{incomplete type 'void' is not assignable}} + *((void *) 0) = 0; // -expected-error {{incomplete type 'void' is not assignable}} double *dp; int *ip; void *vp; diff --git a/test/Sema/deref.c b/test/Sema/deref.c new file mode 100644 index 0000000000..87f1b4862e --- /dev/null +++ b/test/Sema/deref.c @@ -0,0 +1,22 @@ +// RUN: clang -fsyntax-only -verify -std=c90 %s +void +foo (void) +{ + struct b; + struct b* x = 0; + struct b* y = &*x; +} + +void foo2 (void) +{ + typedef int (*arrayptr)[]; + arrayptr x = 0; + arrayptr y = &*x; +} + +void foo3 (void) +{ + void* x = 0; + void* y = &*x; // expected-error {{invalid lvalue in address expression}} +} +