[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