From: John McCall Date: Tue, 15 Nov 2011 01:35:18 +0000 (+0000) Subject: Resolve placeholder expressions before trying to deduce X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32509f1e60451d86e9fbc473b6e853ba10b5fd1e;p=clang Resolve placeholder expressions before trying to deduce 'auto'. Introduce a convenience method to make this a bit easier, and use it elsewhere. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144605 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def index bfcd55bedb..34e6fc5cd8 100644 --- a/include/clang/AST/BuiltinTypes.def +++ b/include/clang/AST/BuiltinTypes.def @@ -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. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index dfa594db1e..c9bee817a8 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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(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 { diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 27730f08f7..f1d5c2d239 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 4f2f8c4eaf..cfa5feabb3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index c24f8aa5e2..3f91bb53e8 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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(); } diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b70c4ca811..3bd671d10c 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -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(); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 93ea89d628..17987da16a 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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; diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp index ceb246eb22..aa22b8f56b 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp @@ -92,7 +92,8 @@ namespace PR10939 { template T g(T); void f(X *x) { - auto value = x->method; // expected-error{{variable 'value' with type 'auto' has incompatible initializer of 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 ''}} if (value) { } auto funcptr = &g; diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm index f148b3395d..0b9c63e30d 100644 --- a/test/SemaObjCXX/properties.mm +++ b/test/SemaObjCXX/properties.mm @@ -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; +}