mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 12:26:52 +08:00
Add support for calls to dependent names within templates, e.g.,
template<typename T> void f(T x) {
g(x); // g is a dependent name, so don't even bother to look it up
g(); // error: g is not a dependent name
}
Note that when we see "g(", we build a CXXDependentNameExpr. However,
if none of the call arguments are type-dependent, we will force the
resolution of the name "g" and replace the CXXDependentNameExpr with
its result.
GCC actually produces a nice error message when you make this
mistake, and even offers to compile your code with -fpermissive. I'll
do the former next, but I don't plan to do the latter.
llvm-svn: 60618
This commit is contained in:
@@ -459,7 +459,8 @@ namespace {
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations. There are guaranteed to be one fewer commas than arguments,
|
||||
/// unless there are zero arguments.
|
||||
virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
|
||||
virtual ExprResult ActOnCallExpr(Scope *S, ExprTy *Fn,
|
||||
SourceLocation LParenLoc,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
|
||||
@@ -632,6 +632,48 @@ 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.
|
||||
/// @code
|
||||
/// template<typename T> void f(T x) {
|
||||
/// g(x); // g is a dependent name.
|
||||
/// }
|
||||
/// @endcode
|
||||
class CXXDependentNameExpr : public Expr {
|
||||
/// Name - The name that was present in the source code.
|
||||
IdentifierInfo *Name;
|
||||
|
||||
/// Loc - The location
|
||||
SourceLocation Loc;
|
||||
|
||||
public:
|
||||
CXXDependentNameExpr(IdentifierInfo *N, QualType T, SourceLocation L)
|
||||
: Expr(CXXDependentNameExprClass, T, true, true), Name(N), Loc(L) { }
|
||||
|
||||
/// getName - Retrieves the name that occurred in the source code.
|
||||
IdentifierInfo *getName() const { return Name; }
|
||||
|
||||
/// getLocation - Retrieves the location in the source code where
|
||||
/// the name occurred.
|
||||
SourceLocation getLocation() const { return Loc; }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXDependentNameExprClass;
|
||||
}
|
||||
static bool classof(const CXXDependentNameExpr *) { 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);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,6 +107,7 @@ STMT(CXXZeroInitValueExpr , Expr)
|
||||
STMT(CXXConditionDeclExpr , DeclRefExpr)
|
||||
STMT(CXXNewExpr , Expr)
|
||||
STMT(CXXDeleteExpr , Expr)
|
||||
STMT(CXXDependentNameExpr , Expr)
|
||||
|
||||
// Obj-C Expressions.
|
||||
STMT(ObjCStringLiteral , Expr)
|
||||
|
||||
@@ -530,7 +530,8 @@ public:
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations. There are guaranteed to be one fewer commas than arguments,
|
||||
/// unless there are zero arguments.
|
||||
virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
|
||||
virtual ExprResult ActOnCallExpr(Scope *S, ExprTy *Fn,
|
||||
SourceLocation LParenLoc,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
|
||||
@@ -112,6 +112,14 @@ 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() {
|
||||
return child_iterator();
|
||||
}
|
||||
Stmt::child_iterator CXXDependentNameExpr::child_end() {
|
||||
return child_iterator();
|
||||
}
|
||||
|
||||
OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
|
||||
// All simple function calls (e.g. func()) are implicitly cast to pointer to
|
||||
// function. As a result, we try and obtain the DeclRefExpr from the
|
||||
|
||||
@@ -988,6 +988,10 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
|
||||
PrintExpr(E->getArgument());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXDependentNameExpr(CXXDependentNameExpr *E) {
|
||||
OS << E->getName()->getName();
|
||||
}
|
||||
|
||||
// Obj-C
|
||||
|
||||
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
|
||||
|
||||
@@ -239,6 +239,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
|
||||
|
||||
case CXXDeleteExprClass:
|
||||
return CXXDeleteExpr::CreateImpl(D, C);
|
||||
|
||||
case CXXDependentNameExprClass:
|
||||
return CXXDependentNameExpr::CreateImpl(D, C);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1506,3 +1509,17 @@ CXXDeleteExpr::CreateImpl(Deserializer& D, ASTContext& C) {
|
||||
return new CXXDeleteExpr(Ty, GlobalDelete, ArrayForm, OperatorDelete,
|
||||
cast<Expr>(Argument), Loc);
|
||||
}
|
||||
|
||||
void CXXDependentNameExpr::EmitImpl(llvm::Serializer& S) const {
|
||||
S.Emit(getType());
|
||||
S.EmitPtr(Name);
|
||||
S.Emit(Loc);
|
||||
}
|
||||
|
||||
CXXDependentNameExpr *
|
||||
CXXDependentNameExpr::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);
|
||||
}
|
||||
|
||||
@@ -740,7 +740,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||
if (!LHS.isInvalid && Tok.is(tok::r_paren)) {
|
||||
assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
|
||||
"Unexpected number of commas!");
|
||||
LHS = Actions.ActOnCallExpr(LHSGuard.take(), Loc, ArgExprs.take(),
|
||||
LHS = Actions.ActOnCallExpr(CurScope, LHSGuard.take(), Loc,
|
||||
ArgExprs.take(),
|
||||
ArgExprs.size(), &CommaLocs[0],
|
||||
Tok.getLocation());
|
||||
LHSGuard.reset(LHS);
|
||||
|
||||
@@ -461,7 +461,7 @@ public:
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
ExprResult
|
||||
BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
|
||||
BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc);
|
||||
@@ -643,7 +643,8 @@ public:
|
||||
ExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
DeclarationName Name,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS);
|
||||
const CXXScopeSpec *SS,
|
||||
bool ForceResolution = false);
|
||||
|
||||
|
||||
virtual ExprResult ActOnPredefinedExpr(SourceLocation Loc,
|
||||
@@ -681,7 +682,8 @@ public:
|
||||
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations.
|
||||
virtual ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
|
||||
virtual ExprResult ActOnCallExpr(Scope *S, ExprTy *Fn,
|
||||
SourceLocation LParenLoc,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc);
|
||||
|
||||
@@ -364,10 +364,29 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
||||
/// function call context. LookupCtx is only used for a C++
|
||||
/// 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.
|
||||
Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
DeclarationName Name,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS) {
|
||||
const CXXScopeSpec *SS,
|
||||
bool ForceResolution) {
|
||||
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 new CXXDependentNameExpr(Name.getAsIdentifierInfo(),
|
||||
Context.DependentTy, Loc);
|
||||
}
|
||||
|
||||
// Could be enum-constant, value decl, instance variable, etc.
|
||||
Decl *D;
|
||||
if (SS && !SS->isEmpty()) {
|
||||
@@ -377,7 +396,7 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
||||
D = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
|
||||
} else
|
||||
D = LookupDecl(Name, Decl::IDNS_Ordinary, S);
|
||||
|
||||
|
||||
// If this reference is in an Objective-C method, then ivar lookup happens as
|
||||
// well.
|
||||
IdentifierInfo *II = Name.getAsIdentifierInfo();
|
||||
@@ -1315,7 +1334,7 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
|
||||
/// This provides the location of the left/right parens and a list of comma
|
||||
/// locations.
|
||||
Action::ExprResult Sema::
|
||||
ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
||||
ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc,
|
||||
ExprTy **args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs, SourceLocation RParenLoc) {
|
||||
Expr *Fn = static_cast<Expr *>(fn);
|
||||
@@ -1324,9 +1343,36 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
||||
FunctionDecl *FDecl = NULL;
|
||||
OverloadedFunctionDecl *Ovl = 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.
|
||||
ExprResult Resolved
|
||||
= ActOnDeclarationNameExpr(S, FnName->getLocation(), FnName->getName(),
|
||||
/*HasTrailingLParen=*/true,
|
||||
/*SS=*/0,
|
||||
/*ForceResolution=*/true);
|
||||
if (Resolved.isInvalid)
|
||||
return true;
|
||||
else {
|
||||
delete Fn;
|
||||
Fn = (Expr *)Resolved.Val;
|
||||
}
|
||||
}
|
||||
} else
|
||||
Dependent = true;
|
||||
} else
|
||||
Dependent = Expr::hasAnyTypeDependentArguments(Args, NumArgs);
|
||||
|
||||
// FIXME: Will need to cache the results of name lookup (including
|
||||
// ADL) in Fn.
|
||||
if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs))
|
||||
if (Dependent)
|
||||
return new CallExpr(Fn, Args, NumArgs, Context.DependentTy, RParenLoc);
|
||||
|
||||
// If we're directly calling a function or a set of overloaded
|
||||
@@ -1358,7 +1404,7 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
||||
}
|
||||
|
||||
if (getLangOptions().CPlusPlus && Fn->getType()->isRecordType())
|
||||
return BuildCallToObjectOfClassType(Fn, LParenLoc, Args, NumArgs,
|
||||
return BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs,
|
||||
CommaLocs, RParenLoc);
|
||||
|
||||
// Promote the function operand.
|
||||
|
||||
@@ -3102,7 +3102,8 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, OverloadedFunctionDecl *Ov
|
||||
/// overloaded function call operator (@c operator()) or performing a
|
||||
/// user-defined conversion on the object argument.
|
||||
Action::ExprResult
|
||||
Sema::BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
|
||||
Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
|
||||
SourceLocation LParenLoc,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
@@ -3220,7 +3221,7 @@ Sema::BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
|
||||
ImpCastExprToType(Object,
|
||||
Conv->getConversionType().getNonReferenceType(),
|
||||
Conv->getConversionType()->isReferenceType());
|
||||
return ActOnCallExpr((ExprTy*)Object, LParenLoc, (ExprTy**)Args, NumArgs,
|
||||
return ActOnCallExpr(S, (ExprTy*)Object, LParenLoc, (ExprTy**)Args, NumArgs,
|
||||
CommaLocs, RParenLoc);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ T f(T x) {
|
||||
(void)(x += 0);
|
||||
(void)(x? x : x);
|
||||
return g(x);
|
||||
// h(x); // h is a dependent name
|
||||
h(x); // h is a dependent name
|
||||
g(1, 1); // expected-error{{too many arguments to function call}}
|
||||
h(1); // expected-error{{use of undeclared identifier 'h'}}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user