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
This commit is contained in:
Steve Naroff 2008-01-13 17:10:08 +00:00
Родитель d880c18293
Коммит 08f1967167
4 изменённых файлов: 40 добавлений и 18 удалений

Просмотреть файл

@ -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<UnaryOperator>(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());

Просмотреть файл

@ -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,

Просмотреть файл

@ -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;

22
test/Sema/deref.c Normal file
Просмотреть файл

@ -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}}
}