diff options
| author | Douglas Gregor <dgregor@apple.com> | 2008-12-06 00:22:45 +0000 | 
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2008-12-06 00:22:45 +0000 | 
| commit | b0846b0f5101ced59627c73d370915e5f2370ace (patch) | |
| tree | dadc73d8abfbd7948d60f88cd8ce67bcedb86cd2 /clang/lib | |
| parent | 35e2cfccafd00304507e3f99ec3ecfa6168326a7 (diff) | |
| download | bcm5719-llvm-b0846b0f5101ced59627c73d370915e5f2370ace.tar.gz bcm5719-llvm-b0846b0f5101ced59627c73d370915e5f2370ace.zip  | |
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
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/AST/StmtSerialization.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 56 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 5 | 
7 files changed, 90 insertions, 11 deletions
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 2d517196be6..b5d5b4c12fd 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -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  diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 2e54777b94f..94bca638663 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -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) { diff --git a/clang/lib/AST/StmtSerialization.cpp b/clang/lib/AST/StmtSerialization.cpp index 6ebaca1c8e5..9b6207be2b7 100644 --- a/clang/lib/AST/StmtSerialization.cpp +++ b/clang/lib/AST/StmtSerialization.cpp @@ -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); +} diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 52caffbb7fc..e31c7a586ef 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 85cd2c873ba..b396e1c185b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e4beb74fc5d..cdca6827049 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 80bb9eda886..8a68d5be5c3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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);    }  | 

