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,
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<
/// - 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.
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
- case VAArgExprClass:
- return LV_NotObjectType;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
case CXXConditionDeclExprClass:
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();
-// RUN: clang-cc -fsyntax-only -verify -std=c90 %s
+/* RUN: clang-cc -fsyntax-only -verify -std=c90 -pedantic %s
+ */
void
foo (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;
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;
__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);
}