Rework the fix-it hint for code like

get_origin->x

where get_origin is actually a function and the user has forgotten the
parentheses. Instead of giving a lame note for the fix-it, give a
full-fledge error, early, then build the call expression to try to
recover. 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86238 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-11-06 06:30:47 +00:00
Родитель 27591ff4fc
Коммит 3f0b5fd3a5
4 изменённых файлов: 46 добавлений и 16 удалений

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

@ -1447,8 +1447,9 @@ def err_typecheck_member_reference_type : Error<
"cannot refer to type member %0 with '%select{.|->}1'">;
def err_typecheck_member_reference_unknown : Error<
"cannot refer to member %0 with '%select{.|->}1'">;
def note_member_reference_needs_call : Note<
"perhaps you meant to call this function with '()'?">;
def err_member_reference_needs_call : Error<
"base of member reference has function type %0; perhaps you meant to call "
"this function with '()'?">;
def warn_subscript_is_char : Warning<"array subscript is of type 'char'">,
InGroup<CharSubscript>, DefaultIgnore;

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

@ -1882,6 +1882,38 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
DefaultFunctionArrayConversion(BaseExpr);
QualType BaseType = BaseExpr->getType();
// If the user is trying to apply -> or . to a function pointer
// type, it's probably because the forgot parentheses to call that
// function. Suggest the addition of those parentheses, build the
// call, and continue on.
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
if (const FunctionProtoType *Fun
= Ptr->getPointeeType()->getAs<FunctionProtoType>()) {
QualType ResultTy = Fun->getResultType();
if (Fun->getNumArgs() == 0 &&
((OpKind == tok::period && ResultTy->isRecordType()) ||
(OpKind == tok::arrow && ResultTy->isPointerType() &&
ResultTy->getAs<PointerType>()->getPointeeType()
->isRecordType()))) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::err_member_reference_needs_call)
<< QualType(Fun, 0)
<< CodeModificationHint::CreateInsertion(Loc, "()");
OwningExprResult NewBase
= ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc,
MultiExprArg(*this, 0, 0), 0, Loc);
if (NewBase.isInvalid())
return move(NewBase);
BaseExpr = NewBase.takeAs<Expr>();
DefaultFunctionArrayConversion(BaseExpr);
BaseType = BaseExpr->getType();
}
}
}
// If this is an Objective-C pseudo-builtin and a definition is provided then
// use that.
if (BaseType->isObjCIdType()) {
@ -2437,18 +2469,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
// If the user is trying to apply -> or . to a function or function
// pointer, it's probably because they forgot parentheses to call
// the function. Suggest the addition of those parentheses.
if (BaseType == Context.OverloadTy ||
BaseType->isFunctionType() ||
(BaseType->isPointerType() &&
BaseType->getAs<PointerType>()->isFunctionType())) {
SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd());
Diag(Loc, diag::note_member_reference_needs_call)
<< CodeModificationHint::CreateInsertion(Loc, "()");
}
return ExprError();
}

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

@ -8,3 +8,13 @@
struct s; // expected-note{{previous use is here}}
union s *s1; // expected-error{{use of 's' with tag type that does not match previous declaration}}
struct Point {
float x, y, z;
};
struct Point *get_origin();
void test_point() {
(void)get_origin->x;
}

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

@ -28,8 +28,7 @@ struct B {
A *f0();
};
int f0(B *b) {
return b->f0->f0; // expected-error{{member reference base type 'struct A *()' is not a structure or union}} \
// expected-note{{perhaps you meant to call this function}}
return b->f0->f0; // expected-error{{perhaps you meant to call this function}}
}
int i;