[cfe-commits] r60618 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def include/clang/Parse/Action.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Parse/ParseExpr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/type-dependent-exprs.cpp
Douglas Gregor
dgregor at apple.com
Fri Dec 5 16:22:45 PST 2008
Author: dgregor
Date: Fri Dec 5 18:22:45 2008
New Revision: 60618
URL: http://llvm.org/viewvc/llvm-project?rev=60618&view=rev
Log:
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.
Modified:
cfe/trunk/Driver/PrintParserCallbacks.cpp
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/StmtNodes.def
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/AST/StmtSerialization.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Fri Dec 5 18:22:45 2008
@@ -459,7 +459,8 @@
/// 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) {
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Dec 5 18:22:45 2008
@@ -632,6 +632,48 @@
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
Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Fri Dec 5 18:22:45 2008
@@ -107,6 +107,7 @@
STMT(CXXConditionDeclExpr , DeclRefExpr)
STMT(CXXNewExpr , Expr)
STMT(CXXDeleteExpr , Expr)
+STMT(CXXDependentNameExpr , Expr)
// Obj-C Expressions.
STMT(ObjCStringLiteral , Expr)
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Dec 5 18:22:45 2008
@@ -530,7 +530,8 @@
/// 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) {
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Dec 5 18:22:45 2008
@@ -112,6 +112,14 @@
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
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Dec 5 18:22:45 2008
@@ -988,6 +988,10 @@
PrintExpr(E->getArgument());
}
+void StmtPrinter::VisitCXXDependentNameExpr(CXXDependentNameExpr *E) {
+ OS << E->getName()->getName();
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
Modified: cfe/trunk/lib/AST/StmtSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtSerialization.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Fri Dec 5 18:22:45 2008
@@ -239,6 +239,9 @@
case CXXDeleteExprClass:
return CXXDeleteExpr::CreateImpl(D, C);
+
+ case CXXDependentNameExprClass:
+ return CXXDependentNameExpr::CreateImpl(D, C);
}
}
@@ -1506,3 +1509,17 @@
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);
+}
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Dec 5 18:22:45 2008
@@ -740,7 +740,8 @@
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);
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Dec 5 18:22:45 2008
@@ -461,7 +461,7 @@
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 @@
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 @@
/// 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);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Dec 5 18:22:45 2008
@@ -364,10 +364,29 @@
/// 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 @@
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 @@
/// 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 @@
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 @@
}
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.
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Dec 5 18:22:45 2008
@@ -3102,7 +3102,8 @@
/// 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 @@
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);
}
Modified: cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp?rev=60618&r1=60617&r2=60618&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-dependent-exprs.cpp Fri Dec 5 18:22:45 2008
@@ -9,6 +9,8 @@
(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;
}
More information about the cfe-commits
mailing list