unqualified-id '('

in C++. The unqualified-id might not refer to any declaration in our
current scope, but declarations by that name might be found via
argument-dependent lookup. We now do so properly.

As part of this change, CXXDependentNameExpr, which was previously
designed to express the unqualified-id in the above constructor within
templates, has become UnresolvedFunctionNameExpr, which does
effectively the same thing but will work for both templates and
non-templates.

Additionally, we cope with all unqualified-ids, since ADL also applies
in cases like

  operator+(x, y)




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63733 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-02-04 15:01:18 +00:00
Родитель 20bcd55e14
Коммит 17330019f0
12 изменённых файлов: 167 добавлений и 126 удалений

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

@ -727,28 +727,35 @@ public:
static CXXDeleteExpr * CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
/// CXXDependentNameExpr - Represents a dependent name in C++ for
/// which we could not locate any definition. These names can only
/// occur as in the example below, with an unqualified call to a
/// function name whose arguments are dependent.
/// \brief Represents the name of a function that has not been
/// resolved to any declaration.
///
/// Unresolved function names occur when a function name is
/// encountered prior to an open parentheses ('(') in a C++ function
/// call, and the function name itself did not resolve to a
/// declaration. These function names can only be resolved when they
/// form the postfix-expression of a function call, so that
/// argument-dependent lookup finds declarations corresponding to
/// these functions.
/// @code
/// template<typename T> void f(T x) {
/// g(x); // g is a dependent name.
/// g(x); // g is an unresolved function name (that is also a dependent name)
/// }
/// @endcode
class CXXDependentNameExpr : public Expr {
/// Name - The name that was present in the source code.
IdentifierInfo *Name;
class UnresolvedFunctionNameExpr : public Expr {
/// The name that was present in the source
DeclarationName Name;
/// Loc - The location
/// The location of this name in the source code
SourceLocation Loc;
public:
CXXDependentNameExpr(IdentifierInfo *N, QualType T, SourceLocation L)
: Expr(CXXDependentNameExprClass, T, true, true), Name(N), Loc(L) { }
UnresolvedFunctionNameExpr(DeclarationName N, QualType T, SourceLocation L)
: Expr(UnresolvedFunctionNameExprClass, T, false, false), Name(N), Loc(L) { }
/// getName - Retrieves the name that occurred in the source code.
IdentifierInfo *getName() const { return Name; }
/// \brief Retrieves the name that occurred in the source code.
DeclarationName getName() const { return Name; }
/// getLocation - Retrieves the location in the source code where
/// the name occurred.
@ -757,16 +764,16 @@ public:
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDependentNameExprClass;
return T->getStmtClass() == UnresolvedFunctionNameExprClass;
}
static bool classof(const CXXDependentNameExpr *) { return true; }
static bool classof(const UnresolvedFunctionNameExpr *) { return true; }
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
virtual void EmitImpl(llvm::Serializer& S) const;
static CXXDependentNameExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
static UnresolvedFunctionNameExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the

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

@ -115,7 +115,7 @@ STMT(CXXZeroInitValueExpr , Expr)
STMT(CXXConditionDeclExpr , DeclRefExpr)
STMT(CXXNewExpr , Expr)
STMT(CXXDeleteExpr , Expr)
STMT(CXXDependentNameExpr , Expr)
STMT(UnresolvedFunctionNameExpr , Expr)
STMT(UnaryTypeTraitExpr , Expr)
STMT(QualifiedDeclRefExpr , DeclRefExpr)

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

@ -120,11 +120,11 @@ Stmt::child_iterator CXXNewExpr::child_end() {
Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
// CXXDependentNameExpr
Stmt::child_iterator CXXDependentNameExpr::child_begin() {
// UnresolvedFunctionNameExpr
Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
return child_iterator();
}
Stmt::child_iterator CXXDependentNameExpr::child_end() {
Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() {
return child_iterator();
}

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

@ -1101,8 +1101,8 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
PrintExpr(E->getArgument());
}
void StmtPrinter::VisitCXXDependentNameExpr(CXXDependentNameExpr *E) {
OS << E->getName()->getName();
void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
OS << E->getName().getAsString();
}
static const char *getTypeTraitName(UnaryTypeTrait UTT) {

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

@ -245,8 +245,8 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
case CXXDeleteExprClass:
return CXXDeleteExpr::CreateImpl(D, C);
case CXXDependentNameExprClass:
return CXXDependentNameExpr::CreateImpl(D, C);
case UnresolvedFunctionNameExprClass:
return UnresolvedFunctionNameExpr::CreateImpl(D, C);
case CXXCatchStmtClass:
return CXXCatchStmt::CreateImpl(D, C);
@ -1528,18 +1528,18 @@ CXXDeleteExpr::CreateImpl(Deserializer& D, ASTContext& C) {
cast<Expr>(Argument), Loc);
}
void CXXDependentNameExpr::EmitImpl(llvm::Serializer& S) const {
void UnresolvedFunctionNameExpr::EmitImpl(llvm::Serializer& S) const {
S.Emit(getType());
S.EmitPtr(Name);
S.EmitPtr(Name.getAsIdentifierInfo()); // FIXME: WRONG!
S.Emit(Loc);
}
CXXDependentNameExpr *
CXXDependentNameExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
UnresolvedFunctionNameExpr *
UnresolvedFunctionNameExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
QualType Ty = QualType::ReadVal(D);
IdentifierInfo *N = D.ReadPtr<IdentifierInfo>();
SourceLocation L = SourceLocation::ReadVal(D);
return new CXXDependentNameExpr(N, Ty, L);
return new UnresolvedFunctionNameExpr(N, Ty, L);
}
void UnaryTypeTraitExpr::EmitImpl(llvm::Serializer& S) const {

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

@ -517,12 +517,13 @@ public:
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Func,
FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc,
bool ArgumentDependentLookup);
bool &ArgumentDependentLookup);
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
@ -1068,7 +1069,6 @@ public:
DeclarationName Name,
bool HasTrailingLParen,
const CXXScopeSpec *SS,
bool ForceResolution = false,
bool isAddressOfOperand = false);
virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,

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

@ -366,7 +366,7 @@ Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
const CXXScopeSpec *SS,
bool isAddressOfOperand) {
return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS,
/*ForceResolution*/false, isAddressOfOperand);
isAddressOfOperand);
}
/// BuildDeclRefExpr - Build either a DeclRefExpr or a
@ -535,10 +535,6 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
/// qualified-id (foo::bar) to indicate the class or namespace that
/// the identifier must be a member of.
///
/// If ForceResolution is true, then we will attempt to resolve the
/// name even if it looks like a dependent name. This option is off by
/// default.
///
/// isAddressOfOperand means that this expression is the direct operand
/// of an address-of operator. This matters because this is the only
/// situation where a qualified name referencing a non-static member may
@ -546,27 +542,27 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
Sema::OwningExprResult
Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
DeclarationName Name, bool HasTrailingLParen,
const CXXScopeSpec *SS, bool ForceResolution,
const CXXScopeSpec *SS,
bool isAddressOfOperand) {
if (S->getTemplateParamParent() && Name.getAsIdentifierInfo() &&
HasTrailingLParen && !SS && !ForceResolution) {
// We've seen something of the form
// identifier(
// and we are in a template, so it is likely that 's' is a
// dependent name. However, we won't know until we've parsed all
// of the call arguments. So, build a CXXDependentNameExpr node
// to represent this name. Then, if it turns out that none of the
// arguments are type-dependent, we'll force the resolution of the
// dependent name at that point.
return Owned(new (Context) CXXDependentNameExpr(Name.getAsIdentifierInfo(),
Context.DependentTy, Loc));
}
// Could be enum-constant, value decl, instance variable, etc.
if (SS && SS->isInvalid())
return ExprError();
LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName);
if (getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
HasTrailingLParen && Lookup.getKind() == LookupResult::NotFound) {
// We've seen something of the form
//
// identifier(
//
// and we did not find any entity by the name
// "identifier". However, this identifier is still subject to
// argument-dependent lookup, so keep track of the name.
return Owned(new (Context) UnresolvedFunctionNameExpr(Name,
Context.OverloadTy,
Loc));
}
Decl *D = 0;
if (Lookup.isAmbiguous()) {
DiagnoseAmbiguousLookup(Lookup, Name, Loc,
@ -1839,48 +1835,27 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
FunctionDecl *FDecl = NULL;
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
bool Dependent = false;
if (Fn->isTypeDependent()) {
if (CXXDependentNameExpr *FnName = dyn_cast<CXXDependentNameExpr>(Fn)) {
if (Expr::hasAnyTypeDependentArguments(Args, NumArgs))
Dependent = true;
else {
// Resolve the CXXDependentNameExpr to an actual identifier;
// it wasn't really a dependent name after all.
// FIXME: in the presence of ADL, this resolves too early.
OwningExprResult Resolved
= ActOnDeclarationNameExpr(S, FnName->getLocation(),
FnName->getName(),
/*HasTrailingLParen=*/true,
/*SS=*/0,
/*ForceResolution=*/true);
if (Resolved.isInvalid())
return ExprError();
else {
delete Fn;
Fn = (Expr *)Resolved.release();
}
}
} else
Dependent = true;
} else
Dependent = Expr::hasAnyTypeDependentArguments(Args, NumArgs);
// FIXME: Will need to cache the results of name lookup (including
// ADL) in Fn.
if (Dependent)
return Owned(new (Context) CallExpr(Fn, Args, NumArgs,
Context.DependentTy, RParenLoc));
// Determine whether this is a call to an object (C++ [over.call.object]).
if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType())
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
// FIXME: Will need to cache the results of name lookup (including ADL) in Fn.
bool Dependent = false;
if (Fn->isTypeDependent())
Dependent = true;
else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs))
Dependent = true;
if (Dependent)
return Owned(new (Context) CallExpr(Fn, Args, NumArgs,
Context.DependentTy, RParenLoc));
// Determine whether this is a call to an object (C++ [over.call.object]).
if (Fn->getType()->isRecordType())
return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
// Determine whether this is a call to a member function.
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
@ -1897,7 +1872,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr))
FnExpr = IcExpr->getSubExpr();
else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) {
// FIXME: Where does the C++ standard say this?
// Parentheses around a function disable ADL
// (C++0x [basic.lookup.argdep]p1).
ADL = false;
FnExpr = PExpr->getSubExpr();
} else if (isa<UnaryOperator>(FnExpr) &&
@ -1905,32 +1881,39 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
== UnaryOperator::AddrOf) {
FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr();
} else {
DRExpr = dyn_cast<DeclRefExpr>(FnExpr);
if (isa<DeclRefExpr>(FnExpr)) {
DRExpr = cast<DeclRefExpr>(FnExpr);
// Qualified names disable ADL (C++0x [basic.lookup.argdep]p1).
ADL = ADL && !isa<QualifiedDeclRefExpr>(DRExpr);
}
else if (UnresolvedFunctionNameExpr *DepName
= dyn_cast<UnresolvedFunctionNameExpr>(FnExpr))
UnqualifiedName = DepName->getName();
else {
// Any kind of name that does not refer to a declaration (or
// set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3).
ADL = false;
}
break;
}
}
if (DRExpr)
OverloadedFunctionDecl *Ovl = 0;
if (DRExpr) {
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
}
if (getLangOptions().CPlusPlus && DRExpr &&
(FDecl || isa<OverloadedFunctionDecl>(DRExpr->getDecl()))) {
// C++ [basic.lookup.argdep]p1:
// When an unqualified name is used as the postfix-expression in
// a function call (5.2.2), other namespaces not considered
// during the usual unqualified lookup (3.4.1) may be searched,
// and namespace-scope friend func- tion declarations (11.4) not
// otherwise visible may be found.
if (DRExpr && isa<QualifiedDeclRefExpr>(DRExpr))
ADL = false;
if (getLangOptions().CPlusPlus && (FDecl || Ovl || UnqualifiedName)) {
// We don't perform ADL for builtins.
if (FDecl && FDecl->getIdentifier() &&
FDecl->getIdentifier()->getBuiltinID())
ADL = false;
if ((DRExpr && isa<OverloadedFunctionDecl>(DRExpr->getDecl())) || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, DRExpr->getDecl(), LParenLoc, Args,
if (Ovl || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
UnqualifiedName, LParenLoc, Args,
NumArgs, CommaLocs, RParenLoc, ADL);
if (!FDecl)
return ExprError();
@ -1938,7 +1921,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
// Update Fn to refer to the actual function selected.
Expr *NewFn = 0;
if (QualifiedDeclRefExpr *QDRExpr
= dyn_cast<QualifiedDeclRefExpr>(DRExpr))
= dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr))
NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(),
QDRExpr->getLocation(),
false, false,

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

@ -35,7 +35,7 @@ Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
DeclarationName ConvName
= Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
&SS, /*ForceRes*/false, isAddressOfOperand);
&SS, isAddressOfOperand);
}
/// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator
@ -51,7 +51,7 @@ Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
bool isAddressOfOperand) {
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op);
return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS,
/*ForceRes*/false, isAddressOfOperand);
isAddressOfOperand);
}
/// ActOnCXXTypeidOfType - Parse typeid( type-id ).

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

@ -3503,20 +3503,56 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
/// resolution. Otherwise, emits diagnostics, deletes all of the
/// arguments and Fn, and returns NULL.
FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
DeclarationName UnqualifiedName,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
SourceLocation *CommaLocs,
SourceLocation RParenLoc,
bool ArgumentDependentLookup) {
bool &ArgumentDependentLookup) {
OverloadCandidateSet CandidateSet;
// Add the functions denoted by Callee to the set of candidate
// functions. While we're doing so, track whether argument-dependent
// lookup still applies, per:
//
// C++0x [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
// lookup (defined as follows). If X contains
//
// -- a declaration of a class member, or
//
// -- a block-scope function declaration that is not a
// using-declaration, or
//
// -- a declaration that is neither a function or a function
// template
//
// then Y is empty.
if (OverloadedFunctionDecl *Ovl
= dyn_cast_or_null<OverloadedFunctionDecl>(Callee))
AddOverloadCandidates(Ovl, Args, NumArgs, CandidateSet);
else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee))
AddOverloadCandidate(cast<FunctionDecl>(Func), Args, NumArgs, CandidateSet);
= dyn_cast_or_null<OverloadedFunctionDecl>(Callee)) {
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
if ((*Func)->getDeclContext()->isRecord() ||
(*Func)->getDeclContext()->isFunctionOrMethod())
ArgumentDependentLookup = false;
}
} else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
AddOverloadCandidate(Func, Args, NumArgs, CandidateSet);
if (Func->getDeclContext()->isRecord() ||
Func->getDeclContext()->isFunctionOrMethod())
ArgumentDependentLookup = false;
}
if (Callee)
UnqualifiedName = Callee->getDeclName();
if (ArgumentDependentLookup)
AddArgumentDependentLookupCandidates(Callee->getDeclName(), Args, NumArgs,
AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs,
CandidateSet);
OverloadCandidateSet::iterator Best;
@ -3527,14 +3563,14 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
case OR_No_Viable_Function:
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
<< Callee->getDeclName() << (unsigned)CandidateSet.size()
<< UnqualifiedName << (unsigned)CandidateSet.size()
<< Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
break;
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
<< Callee->getDeclName() << Fn->getSourceRange();
<< UnqualifiedName << Fn->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
break;
}

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

@ -6,7 +6,7 @@ namespace N {
X operator+(X, X);
void f(X);
void g(X);
void g(X); // expected-note{{candidate function}}
void test_multiadd(X x) {
(void)(x + x);
@ -39,7 +39,22 @@ namespace N {
void test_func_adl_only(N::X x) {
// FIXME: here, despite the fact that the name lookup for 'g' fails,
// this is well-formed code. The fix will go into Sema::ActOnCallExpr.
// g(x);
g(x);
}
namespace M {
int g(N::X); // expected-note{{candidate function}}
void test(N::X x) {
g(x); // expected-error{{call to 'g' is ambiguous; candidates are:}}
int i = (g)(x);
int g(N::X);
g(x); // okay; calls locally-declared function, no ADL
}
}
void test_operator_name_adl(N::X x) {
(void)operator+(x, x);
}

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

@ -9,7 +9,7 @@ public:
}
float g() {
return operator float(); // expected-error{{use of undeclared 'operator float'}}
return operator float(); // expected-error{{no matching function for call to 'operator float'}}
}
};

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

@ -19,6 +19,6 @@ T f(T x) {
return g(x);
h(x); // h is a dependent name
g(1, 1); // expected-error{{no matching function for call}}
h(1); // expected-error{{use of undeclared identifier 'h'}}
h(1); // expected-error{{no matching function for call to 'h'}}
return 0;
}