Resolve placeholder expressions before trying to deduce

'auto'.  Introduce a convenience method to make this a bit
easier, and use it elsewhere.

llvm-svn: 144605
This commit is contained in:
John McCall 2011-11-15 01:35:18 +00:00
parent 9957e8b789
commit d5c98ae695
9 changed files with 58 additions and 24 deletions

View File

@ -170,6 +170,9 @@ BUILTIN_TYPE(Dependent, DependentTy)
// &x->foo # only if might be a static member function
// &Class::foo # when a pointer-to-member; sub-expr also has this type
// OverloadExpr::find can be used to analyze the expression.
//
// Overload should be the first placeholder type, or else change
// BuiltinType::isNonOverloadPlaceholderType()
PLACEHOLDER_TYPE(Overload, OverloadTy)
// The type of a bound C++ non-static member function.

View File

@ -1367,6 +1367,10 @@ public:
/// isSpecificPlaceholderType - Test for a specific placeholder type.
bool isSpecificPlaceholderType(unsigned K) const;
/// isNonOverloadPlaceholderType - Test for a placeholder type
/// other than Overload; see BuiltinType::isNonOverloadPlaceholderType.
bool isNonOverloadPlaceholderType() const;
/// isIntegerType() does *not* include complex integers (a GCC extension).
/// isComplexIntegerType() can be used to test for complex integers.
bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
@ -1725,6 +1729,19 @@ public:
return isPlaceholderTypeKind(getKind());
}
/// Determines whether this type is a placeholder type other than
/// Overload. Most placeholder types require only syntactic
/// information about their context in order to be resolved (e.g.
/// whether it is a call expression), which means they can (and
/// should) be resolved in an earlier "phase" of analysis.
/// Overload expressions sometimes pick up further information
/// from their context, like whether the context expects a
/// specific function-pointer type, and so frequently need
/// special treatment.
bool isNonOverloadPlaceholderType() const {
return getKind() > Overload;
}
static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
static bool classof(const BuiltinType *) { return true; }
};
@ -4710,6 +4727,12 @@ inline bool Type::isSpecificPlaceholderType(unsigned K) const {
return false;
}
inline bool Type::isNonOverloadPlaceholderType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(this))
return BT->isNonOverloadPlaceholderType();
return false;
}
/// \brief Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {

View File

@ -4624,7 +4624,7 @@ public:
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *Initializer,
bool DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer,
TypeSourceInfo *&Result);
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,

View File

@ -3976,10 +3976,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
for (unsigned I = 0; I != NumInit; ++I) {
if (const BuiltinType *pty
= InitList[I]->getType()->getAsPlaceholderType()) {
if (pty->getKind() == BuiltinType::Overload) continue;
if (InitList[I]->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(InitList[I]);
// Ignore failures; dropping the entire initializer list because

View File

@ -3795,17 +3795,14 @@ InitializationSequence::InitializationSequence(Sema &S,
setSequenceKind(NormalSequence);
for (unsigned I = 0; I != NumArgs; ++I)
if (const BuiltinType *PlaceholderTy
= Args[I]->getType()->getAsPlaceholderType()) {
if (Args[I]->getType()->isNonOverloadPlaceholderType()) {
// FIXME: should we be doing this here?
if (PlaceholderTy->getKind() != BuiltinType::Overload) {
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
if (result.isInvalid()) {
SetFailed(FK_PlaceholderType);
return;
}
Args[I] = result.take();
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
if (result.isInvalid()) {
SetFailed(FK_PlaceholderType);
return;
}
Args[I] = result.take();
}

View File

@ -775,12 +775,10 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
VK_RValue, OK_Ordinary, opcLoc);
// Filter out non-overload placeholder types in the RHS.
if (const BuiltinType *PTy = RHS->getType()->getAsPlaceholderType()) {
if (PTy->getKind() != BuiltinType::Overload) {
ExprResult result = CheckPlaceholderExpr(RHS);
if (result.isInvalid()) return ExprError();
RHS = result.take();
}
if (RHS->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(RHS);
if (result.isInvalid()) return ExprError();
RHS = result.take();
}
Expr *opaqueRef = LHS->IgnoreParens();

View File

@ -3342,8 +3342,14 @@ namespace {
///
/// \returns true if deduction succeeded, false if it failed.
bool
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init,
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init,
TypeSourceInfo *&Result) {
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult result = CheckPlaceholderExpr(Init);
if (result.isInvalid()) return false;
Init = result.take();
}
if (Init->isTypeDependent()) {
Result = Type;
return true;

View File

@ -92,7 +92,8 @@ namespace PR10939 {
template<typename T> T g(T);
void f(X *x) {
auto value = x->method; // expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
// FIXME: we should really only get the first diagnostic here.
auto value = x->method; // expected-error {{reference to non-static member function must be called}} expected-error{{variable 'value' with type 'auto' has incompatible initializer of type '<bound member function type>'}}
if (value) { }
auto funcptr = &g<int>;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
struct X {
void f() const;
@ -19,6 +19,15 @@ struct X {
- (void)setx:(const X&)other { x_ = other; }
- (void)method {
self.x.f();
}
}
@end
// rdar://problem/10444030
@interface Test2
- (void) setY: (int) y;
- (int) z;
@end
void test2(Test2 *a) {
auto y = a.y; // expected-error {{expected getter method not found on object of type 'Test2 *'}} expected-error {{variable 'y' with type 'auto' has incompatible initializer of type}}
auto z = a.z;
}