[cfe-commits] r126266 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/SemaCXX/PR7944.cpp test/SemaCXX/member-expr.cpp
Matt Beaumont-Gay
matthewbg at google.com
Tue Feb 22 15:52:53 PST 2011
Author: matthewbg
Date: Tue Feb 22 17:52:53 2011
New Revision: 126266
URL: http://llvm.org/viewvc/llvm-project?rev=126266&view=rev
Log:
Clean up the error recovery at the bottom of Sema::LookupMemberExpr. This
mostly just shuffles various possibilities for recovery into a more
straightforward order, but also unifies a couple of diagnostics.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaCXX/PR7944.cpp
cfe/trunk/test/SemaCXX/member-expr.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=126266&r1=126265&r2=126266&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 22 17:52:53 2011
@@ -2399,13 +2399,10 @@
def err_typecheck_member_reference_unknown : Error<
"cannot refer to member %0 in %1 with '%select{.|->}2'">;
def err_member_reference_needs_call : Error<
- "base of member reference is an overloaded function; perhaps you meant "
- "to call %select{it|the 0-argument overload}0?">;
+ "base of member reference is %select{a function|an overloaded function}0; "
+ "perhaps you meant to call it%select{| with no arguments}1?">;
def note_member_ref_possible_intended_overload : Note<
"possibly valid overload here">;
-def err_member_reference_needs_call_zero_arg : 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;
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=126266&r1=126265&r2=126266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 22 17:52:53 2011
@@ -3980,131 +3980,130 @@
// Failure cases.
fail:
- // There's a possible road to recovery for function types.
- const FunctionType *Fun = 0;
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr->getLocEnd());
-
+ // Recover from dot accesses to pointers, e.g.:
+ // type *foo;
+ // foo.bar
+ // This is actually well-formed in two cases:
+ // - 'type' is an Objective C type
+ // - 'bar' is a pseudo-destructor name which happens to refer to
+ // the appropriate pointer type
if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
- // fall out, handled below.
-
- // Recover from dot accesses to pointers, e.g.:
- // type *foo;
- // foo.bar
- // This is actually well-formed in two cases:
- // - 'type' is an Objective C type
- // - 'bar' is a pseudo-destructor name which happens to refer to
- // the appropriate pointer type
- } else if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
- MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
+ if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
+ MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, "->");
+ << BaseType << int(IsArrow) << BaseExpr->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, "->");
// Recurse as an -> access.
IsArrow = true;
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
}
- } else {
- Fun = BaseType->getAs<FunctionType>();
}
- // If the user is trying to apply -> or . to a function pointer
- // type, it's probably because they forgot parentheses to call that
- // function. Suggest the addition of those parentheses, build the
- // call, and continue on.
- if (Fun || BaseType == Context.OverloadTy) {
- bool TryCall;
- if (BaseType == Context.OverloadTy) {
- // Plunder the overload set for something that would make the member
- // expression valid.
- const OverloadExpr *Overloads = cast<OverloadExpr>(BaseExpr);
- UnresolvedSet<4> CandidateOverloads;
- bool HasZeroArgCandidateOverload = false;
- for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
- DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
- const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- CandidateOverloads.addDecl(*it);
- if (OverloadDecl->getNumParams() == 0) {
- HasZeroArgCandidateOverload = true;
- }
+ // If the user is trying to apply -> or . to a function name, it's probably
+ // because they forgot parentheses to call that function.
+ bool TryCall = false;
+ bool Overloaded = false;
+ UnresolvedSet<8> AllOverloads;
+ if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr)) {
+ AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
+ TryCall = true;
+ Overloaded = true;
+ } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr)) {
+ if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+ AllOverloads.addDecl(Fun);
+ TryCall = true;
+ }
+ }
+
+ if (TryCall) {
+ // Plunder the overload set for something that would make the member
+ // expression valid.
+ UnresolvedSet<4> ViableOverloads;
+ bool HasViableZeroArgOverload = false;
+ for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
+ DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it);
+ QualType ResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType())) {
+ ViableOverloads.addDecl(*it);
+ if (OverloadDecl->getMinRequiredArguments() == 0) {
+ HasViableZeroArgOverload = true;
}
}
- if (HasZeroArgCandidateOverload && CandidateOverloads.size() == 1) {
- // We have one reasonable overload, and there's only one way to call it,
- // so emit a fixit and try to recover
- Diag(ParenInsertionLoc, diag::err_member_reference_needs_call)
- << 1
- << BaseExpr->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- TryCall = true;
- } else {
- Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
- << 0
- << BaseExpr->getSourceRange();
- int CandidateOverloadCount = CandidateOverloads.size();
- int I;
- for (I = 0; I < CandidateOverloadCount; ++I) {
- // FIXME: Magic number for max shown overloads stolen from
- // OverloadCandidateSet::NoteCandidates.
- if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
- break;
- }
- Diag(CandidateOverloads[I].getDecl()->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
- }
- if (I != CandidateOverloadCount) {
- Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
- << int(CandidateOverloadCount - I);
+ }
+
+ if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
+ Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ << 1 << 0
+ << BaseExpr->getSourceRange();
+ int ViableOverloadCount = ViableOverloads.size();
+ int I;
+ for (I = 0; I < ViableOverloadCount; ++I) {
+ // FIXME: Magic number for max shown overloads stolen from
+ // OverloadCandidateSet::NoteCandidates.
+ if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ break;
}
- return ExprError();
+ Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
+ diag::note_member_ref_possible_intended_overload);
}
- } else {
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
- TryCall = (FPT->getNumArgs() == 0);
- } else {
- TryCall = true;
+ if (I != ViableOverloadCount) {
+ Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates)
+ << int(ViableOverloadCount - I);
}
-
- if (TryCall) {
- QualType ResultTy = Fun->getResultType();
- TryCall = (!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getAs<PointerType>()->getPointeeType()->isRecordType());
+ return ExprError();
+ }
+ } else {
+ // We don't have an expression that's convenient to get a Decl from, but we
+ // can at least check if the type is "function of 0 arguments which returns
+ // an acceptable type".
+ const FunctionType *Fun = NULL;
+ if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
+ if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
+ TryCall = true;
}
+ } else if ((Fun = BaseType->getAs<FunctionType>())) {
+ TryCall = true;
}
-
if (TryCall) {
- if (Fun) {
- Diag(BaseExpr->getExprLoc(),
- diag::err_member_reference_needs_call_zero_arg)
- << QualType(Fun, 0)
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
+ if (FPT->getNumArgs() == 0) {
+ QualType ResultTy = Fun->getResultType();
+ TryCall = (!IsArrow && ResultTy->isRecordType()) ||
+ (IsArrow && ResultTy->isPointerType() &&
+ ResultTy->getPointeeType()->isRecordType());
+ }
}
-
- ExprResult NewBase
- = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
- MultiExprArg(*this, 0, 0), ParenInsertionLoc);
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase.takeAs<Expr>();
-
-
- DefaultFunctionArrayConversion(BaseExpr);
- BaseType = BaseExpr->getType();
-
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
}
}
+ if (TryCall) {
+ // At this point, we know BaseExpr looks like it's potentially callable with
+ // 0 arguments, and that it returns something of a reasonable type, so we
+ // can emit a fixit and carry on pretending that BaseExpr was actually a
+ // CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr->getLocEnd());
+ Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call)
+ << int(Overloaded) << 1
+ << BaseExpr->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ ExprResult NewBase = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc);
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase.takeAs<Expr>();
+ DefaultFunctionArrayConversion(BaseExpr);
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
+ }
+
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr->getSourceRange();
Modified: cfe/trunk/test/SemaCXX/PR7944.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/PR7944.cpp?rev=126266&r1=126265&r2=126266&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/PR7944.cpp (original)
+++ cfe/trunk/test/SemaCXX/PR7944.cpp Tue Feb 22 17:52:53 2011
@@ -8,5 +8,5 @@
void g() {
A a;
- MACRO(a.b->f()); // expected-error{{base of member reference has function type}}
+ MACRO(a.b->f()); // expected-error{{base of member reference is a function}}
}
Modified: cfe/trunk/test/SemaCXX/member-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-expr.cpp?rev=126266&r1=126265&r2=126266&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-expr.cpp Tue Feb 22 17:52:53 2011
@@ -28,7 +28,7 @@
A *f0();
};
int f0(B *b) {
- return b->f0->f0; // expected-error{{perhaps you meant to call this function}}
+ return b->f0->f0; // expected-error{{perhaps you meant to call it with no arguments}}
}
int i;
@@ -121,7 +121,7 @@
S fun();
int fun(int i);
int g() {
- return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call the 0-argument overload?}}
+ return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
}
S fun2(); // expected-note{{possibly valid overload here}}
@@ -129,4 +129,10 @@
int g2() {
return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
}
+
+ S fun3(int i=0);
+ int fun3(int i, int j);
+ int g3() {
+ return fun3.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
+ }
}
More information about the cfe-commits
mailing list