]> granicus.if.org Git - clang/commitdiff
Implement template instantiation for several more kinds of expressions:
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 Mar 2009 21:01:28 +0000 (21:01 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 Mar 2009 21:01:28 +0000 (21:01 +0000)
  - C++ function casts, e.g., T(foo)
  - sizeof(), alignof()

More importantly, this allows us to verify that we're performing
overload resolution during template instantiation, with
argument-dependent lookup and the "cached" results of name lookup from
the template definition.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66947 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
Driver/RewriteObjC.cpp
include/clang/AST/Expr.h
include/clang/AST/ExprCXX.h
lib/AST/ExprCXX.cpp
lib/AST/StmtSerialization.cpp
lib/AST/Type.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/SemaTemplate/instantiate-expr-1.cpp

index 1e2cac39de90bd0a2fce6787ce2db7699394c035..c3cc2c3852ae793f56200667bded36780492aafa 100644 (file)
@@ -2553,8 +2553,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
                                             FT->getResultType(), SourceLocation());
     
     // Build sizeof(returnType)
-    SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, true,
-                                      returnType.getAsOpaquePtr(),
+    SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, 
+                                      returnType,
                                       Context->getSizeType(),
                                       SourceLocation(), SourceLocation());
     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
index 3af207789c1e7d89c5d9aa2671e98813baa9effc..bfd8538788690e637ee7909435bce728a999b816 100644 (file)
@@ -692,20 +692,26 @@ class SizeOfAlignOfExpr : public Expr {
   } Argument;
   SourceLocation OpLoc, RParenLoc;
 public:
-  SizeOfAlignOfExpr(bool issizeof, bool istype, void *argument,
+  SizeOfAlignOfExpr(bool issizeof, QualType T, 
                     QualType resultType, SourceLocation op,
                     SourceLocation rp) :
       Expr(SizeOfAlignOfExprClass, resultType,
-           false, // Never type-dependent.
+           false, // Never type-dependent (C++ [temp.dep.expr]p3).
            // Value-dependent if the argument is type-dependent.
-           (istype ? QualType::getFromOpaquePtr(argument)->isDependentType()
-                   : static_cast<Expr*>(argument)->isTypeDependent())),
-      isSizeof(issizeof), isType(istype), OpLoc(op), RParenLoc(rp) {
-    if (isType)
-      Argument.Ty = argument;
-    else
-      // argument was an Expr*, so cast it back to that to be safe
-      Argument.Ex = static_cast<Expr*>(argument);
+           T->isDependentType()),
+      isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) {
+    Argument.Ty = T.getAsOpaquePtr();
+  }
+
+  SizeOfAlignOfExpr(bool issizeof, Expr *E, 
+                    QualType resultType, SourceLocation op,
+                    SourceLocation rp) :
+      Expr(SizeOfAlignOfExprClass, resultType,
+           false, // Never type-dependent (C++ [temp.dep.expr]p3).
+           // Value-dependent if the argument is type-dependent.
+           E->isTypeDependent()),
+      isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) {
+    Argument.Ex = E;
   }
 
   virtual void Destroy(ASTContext& C);
index 37fead0cbf9b9ff010c1099c9ef41142c15b8063..8bf91c2c61f37b27eeb97296bdc6b7b341b7d809 100644 (file)
@@ -467,6 +467,8 @@ public:
   const_arg_iterator arg_begin() const { return Args; }
   const_arg_iterator arg_end() const { return Args + NumArgs; }
   
+  unsigned getNumArgs() const { return NumArgs; }
+
   virtual SourceRange getSourceRange() const {
     return SourceRange(TyBeginLoc, RParenLoc);
   }
index 184c9fe49043d2fa877b8c872af5a46fad71bd2b..1d4a3ba3a6367bf14e9319a5ed40471d5bc2fb2c 100644 (file)
@@ -216,7 +216,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(CXXConstructorDecl *Cons,
                                                Expr **Args,
                                                unsigned NumArgs, 
                                                SourceLocation rParenLoc)
-  : Expr(CXXTemporaryObjectExprClass, writtenTy),
+  : Expr(CXXTemporaryObjectExprClass, writtenTy,
+         writtenTy->isDependentType(),
+         (writtenTy->isDependentType() ||
+          CallExpr::hasAnyValueDependentArguments(Args, NumArgs))),
     TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc),
     Constructor(Cons), Args(0), NumArgs(NumArgs) {
   if (NumArgs > 0) {
index 4a90edd7a1eba8b15c15777693269a3a52edd774..78366a1514f0f91816c65cfee1484677a35c8ce4 100644 (file)
@@ -832,9 +832,14 @@ SizeOfAlignOfExpr::CreateImpl(Deserializer& D, ASTContext& C) {
   QualType Res = QualType::ReadVal(D);
   SourceLocation OpLoc = SourceLocation::ReadVal(D);
   SourceLocation RParenLoc = SourceLocation::ReadVal(D);
-  
-  return new SizeOfAlignOfExpr(isSizeof, isType, Argument, Res,
-                               OpLoc, RParenLoc);
+
+  if (isType)
+    return new (C) SizeOfAlignOfExpr(isSizeof, 
+                                     QualType::getFromOpaquePtr(Argument),
+                                     Res, OpLoc, RParenLoc);
+
+  return new (C) SizeOfAlignOfExpr(isSizeof, (Expr *)Argument,
+                                   Res, OpLoc, RParenLoc);
 }
 
 void StmtExpr::EmitImpl(Serializer& S) const {
index 1b7fc1be4a55e367a91a259e9920dc42e494baed..fc71097c123757b3eaf1b5f992f14cb896caa6cf 100644 (file)
@@ -967,9 +967,12 @@ ClassTemplateSpecializationType(TemplateDecl *T, const TemplateArgument *Args,
 }
 
 void ClassTemplateSpecializationType::Destroy(ASTContext& C) {
-  for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
-    if (Expr *E = getArg(Arg).getAsExpr())
-      E->Destroy(C);
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    // FIXME: Not all expressions get cloned, so we can't yet perform
+    // this destruction.
+    //    if (Expr *E = getArg(Arg).getAsExpr())
+    //      E->Destroy(C);
+  }
 }
 
 ClassTemplateSpecializationType::iterator
index c6fe6c164af8aa88a6bb5458be73a57a7d01426e..b29790e7b5c11ad0e9bb3cafa809511634cd1b56 100644 (file)
@@ -1188,6 +1188,11 @@ public:
     ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
                            void *TyOrEx, const SourceRange &ArgRange);
 
+  OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, 
+                                           bool isSizeOf, SourceRange R);
+  OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, 
+                                           bool isSizeOf, SourceRange R);
+                                           
   bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R);
   bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
                                  const SourceRange &R, bool isSizeof);
index 0855932ac4375ea62583a587ab056efc969cd430..c04006cb1ca1a88994d05d2635606187ced1de54 100644 (file)
@@ -1220,6 +1220,50 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc,
   return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false);
 }
 
+/// \brief Build a sizeof or alignof expression given a type operand.
+Action::OwningExprResult 
+Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, 
+                              bool isSizeOf, SourceRange R) {
+  if (T.isNull())
+    return ExprError();
+
+  if (!T->isDependentType() &&
+      CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf))
+    return ExprError();
+
+  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+  return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T,
+                                               Context.getSizeType(), OpLoc,
+                                               R.getEnd()));
+}
+
+/// \brief Build a sizeof or alignof expression given an expression
+/// operand.
+Action::OwningExprResult 
+Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, 
+                              bool isSizeOf, SourceRange R) {
+  // Verify that the operand is valid.
+  bool isInvalid = false;
+  if (E->isTypeDependent()) {
+    // Delay type-checking for type-dependent expressions.
+  } else if (!isSizeOf) {
+    isInvalid = CheckAlignOfExpr(E, OpLoc, R);
+  } else if (E->isBitField()) {  // C99 6.5.3.4p1.
+    Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
+    isInvalid = true;
+  } else {
+    isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true);
+  }
+
+  if (isInvalid)
+    return ExprError();
+
+  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+  return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E,
+                                               Context.getSizeType(), OpLoc,
+                                               R.getEnd()));
+}
+
 /// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and
 /// the same for @c alignof and @c __alignof
 /// Note that the ArgRange is invalid if isType is false.
@@ -1229,42 +1273,20 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
   // If error parsing type, ignore.
   if (TyOrEx == 0) return ExprError();
 
-  QualType ArgTy;
-  SourceRange Range;
   if (isType) {
-    ArgTy = QualType::getFromOpaquePtr(TyOrEx);
-    Range = ArgRange;
-    
-    // Verify that the operand is valid.
-    if (CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, isSizeof))
-      return ExprError();
-  } else {
-    // Get the end location.
-    Expr *ArgEx = (Expr *)TyOrEx;
-    Range = ArgEx->getSourceRange();
-    ArgTy = ArgEx->getType();
-    
-    // Verify that the operand is valid.
-    bool isInvalid;
-    if (!isSizeof) {
-      isInvalid = CheckAlignOfExpr(ArgEx, OpLoc, Range);
-    } else if (ArgEx->isBitField()) {  // C99 6.5.3.4p1.
-      Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
-      isInvalid = true;
-    } else {
-      isInvalid = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, Range, true);
-    }
-    
-    if (isInvalid) {
-      DeleteExpr(ArgEx);
-      return ExprError();
-    }
-  }
+    QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx);
+    return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange);
+  } 
 
-  // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
-  return Owned(new (Context) SizeOfAlignOfExpr(isSizeof, isType, TyOrEx,
-                                               Context.getSizeType(), OpLoc,
-                                               Range.getEnd()));
+  // Get the end location.
+  Expr *ArgEx = (Expr *)TyOrEx;
+  Action::OwningExprResult Result
+    = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange());
+
+  if (Result.isInvalid())
+    DeleteExpr(ArgEx);
+
+  return move(Result);
 }
 
 QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) {
index 501eda74438bdc9e95ec129cde7a7bdc6ef5554b..e5a252043ed9f3a1f484193be582fcf9995be7b2 100644 (file)
@@ -122,6 +122,13 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
   SourceLocation TyBeginLoc = TypeRange.getBegin();
   SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc);
 
+  if (Ty->isDependentType() || 
+      CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) {
+    return new (Context) CXXTemporaryObjectExpr(0, Ty, TyBeginLoc,
+                                                Exprs, NumExprs, RParenLoc);
+  }
+
+
   // C++ [expr.type.conv]p1:
   // If the expression list is a single expression, the type conversion
   // expression is equivalent (in definedness, and if defined in meaning) to the
@@ -134,8 +141,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
                                                TyBeginLoc, Exprs[0], RParenLoc);
   }
 
-  // FIXME: What AST node to create when the type is dependent?
-
   if (const RecordType *RT = Ty->getAsRecordType()) {
     CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl());
     
index d391c07b3f0ce7a057c8608fd716d6f65e7a3833..57683b30ecd02746ba8e9739ed567655743c3163 100644 (file)
@@ -1392,6 +1392,9 @@ static bool
 IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
                                        QualType T1, QualType T2,
                                        ASTContext &Context) {
+  if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
+    return true;
+
   if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
     return true;
 
index 6fc4515571773fd4b1871b6068b6805ba29dbc31..3780259d43b02b7dadc35692780f1012ab5274a3 100644 (file)
@@ -1275,7 +1275,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
       QualType IntegerType = Context.getCanonicalType(ParamType);
       if (const EnumType *Enum = IntegerType->getAsEnumType())
         IntegerType = Enum->getDecl()->getIntegerType();
-      
+
+      if (Arg->isValueDependent()) {
+        // The argument is value-dependent. Create a new
+        // TemplateArgument with the converted expression.
+        Converted->push_back(TemplateArgument(Arg));
+        return false;
+      } 
+
       llvm::APInt CanonicalArg(Context.getTypeSize(IntegerType), 0, 
                                IntegerType->isSignedIntegerType());
       CanonicalArg = Value;
index b3e4148a6a67443499c1bc4506dac31f4c1d0818..4bd7ad4e83f24ca428070c975d9be61dbd805d9e 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Parse/DeclSpec.h"
+#include "clang/Lex/Preprocessor.h" // for the identifier table
 #include "clang/Basic/LangOptions.h"
 #include "llvm/Support/Compiler.h"
 
@@ -441,7 +442,12 @@ InstantiateClassTemplateSpecializationType(
       break;
 
     case TemplateArgument::Expression:
-      assert(false && "Cannot instantiate expressions yet");
+      Sema::OwningExprResult E 
+        = SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs,
+                                  NumTemplateArgs);
+      if (E.isInvalid())
+        return QualType();
+      InstantiatedTemplateArgs.push_back((Expr *)E.release());
       break;
     }
   }
@@ -564,6 +570,8 @@ namespace {
     unsigned NumTemplateArgs;
 
   public:
+    typedef Sema::OwningExprResult OwningExprResult;
+
     TemplateExprInstantiator(Sema &SemaRef, 
                              const TemplateArgument *TemplateArgs,
                              unsigned NumTemplateArgs)
@@ -573,11 +581,13 @@ namespace {
     // FIXME: Once we get closer to completion, replace these
     // manually-written declarations with automatically-generated ones
     // from clang/AST/StmtNodes.def.
-    Sema::OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
-    Sema::OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
-    Sema::OwningExprResult VisitParenExpr(ParenExpr *E);
-    Sema::OwningExprResult VisitBinaryOperator(BinaryOperator *E);
-    Sema::OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+    OwningExprResult VisitIntegerLiteral(IntegerLiteral *E);
+    OwningExprResult VisitDeclRefExpr(DeclRefExpr *E);
+    OwningExprResult VisitParenExpr(ParenExpr *E);
+    OwningExprResult VisitBinaryOperator(BinaryOperator *E);
+    OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
+    OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+    OwningExprResult VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
 
     // Base case. I'm supposed to ignore this.
     Sema::OwningExprResult VisitStmt(Stmt *) { 
@@ -692,6 +702,9 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
     DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
     OverloadedFunctionDecl *Overloads 
       = cast<OverloadedFunctionDecl>(DRE->getDecl());
+
+    // FIXME: Do we have to check
+    // IsAcceptableNonMemberOperatorCandidate for each of these?
     for (OverloadedFunctionDecl::function_iterator 
            F = Overloads->function_begin(),
            FEnd = Overloads->function_end();
@@ -716,6 +729,90 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   return move(Result);  
 }
 
+Sema::OwningExprResult 
+TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+  bool isSizeOf = E->isSizeOf();
+
+  if (E->isArgumentType()) {
+    QualType T = E->getArgumentType();
+    if (T->isDependentType()) {
+      T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
+                                  /*FIXME*/E->getOperatorLoc(),
+                                  &SemaRef.PP.getIdentifierTable().get("sizeof"));
+      if (T.isNull())
+        return SemaRef.ExprError();
+    }
+
+    return SemaRef.CreateSizeOfAlignOfExpr(T, E->getOperatorLoc(), isSizeOf,
+                                           E->getSourceRange());
+  } 
+
+  Sema::OwningExprResult Arg = Visit(E->getArgumentExpr());
+  if (Arg.isInvalid())
+    return SemaRef.ExprError();
+
+  Sema::OwningExprResult Result
+    = SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
+                                      isSizeOf, E->getSourceRange());
+  if (Result.isInvalid())
+    return SemaRef.ExprError();
+
+  Arg.release();
+  return move(Result);
+}
+
+Sema::OwningExprResult 
+TemplateExprInstantiator::VisitCXXTemporaryObjectExpr(
+                                                  CXXTemporaryObjectExpr *E) {
+  QualType T = E->getType();
+  if (T->isDependentType()) {
+    T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
+                                E->getTypeBeginLoc(), DeclarationName());
+    if (T.isNull())
+      return SemaRef.ExprError();
+  }
+
+  llvm::SmallVector<Expr *, 16> Args;
+  Args.reserve(E->getNumArgs());
+  bool Invalid = false;
+  for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(), 
+                                         ArgEnd = E->arg_end();
+       Arg != ArgEnd; ++Arg) {
+    OwningExprResult InstantiatedArg = Visit(*Arg);
+    if (InstantiatedArg.isInvalid()) {
+      Invalid = true;
+      break;
+    }
+
+    Args.push_back((Expr *)InstantiatedArg.release());
+  }
+
+  if (!Invalid) {
+    SourceLocation CommaLoc;
+    // FIXME: HACK!
+    if (Args.size() > 1)
+      CommaLoc 
+        = SemaRef.PP.getLocForEndOfToken(Args[0]->getSourceRange().getEnd());
+    Sema::ExprResult Result 
+      = SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()
+                                                      /*, FIXME*/),
+                                          T.getAsOpaquePtr(),
+                                          /*FIXME*/E->getTypeBeginLoc(),
+                                          (void**)&Args[0], Args.size(),
+                                          /*HACK*/&CommaLoc,
+                                          E->getSourceRange().getEnd());
+    if (!Result.isInvalid())
+      return SemaRef.Owned(Result);
+  }
+
+  // Clean up the instantiated arguments.
+  // FIXME: Would rather do this with RAII.
+  for (unsigned Idx = 0; Idx < Args.size(); ++Idx)
+    SemaRef.DeleteExpr(Args[Idx]);
+
+  return SemaRef.ExprError();
+}
+
 Sema::OwningExprResult 
 Sema::InstantiateExpr(Expr *E, const TemplateArgument *TemplateArgs,
                       unsigned NumTemplateArgs) {
index 6fceddf05b5ca682e813ea014da423f283ff1cc0..869d558e33328d962878f3fd33f59333205b8b36 100644 (file)
@@ -43,3 +43,13 @@ void test_BitfieldDivide() {
   (void)sizeof(BitfieldDivide<5, 1>);
   (void)sizeof(BitfieldDivide<5, 0>); // expected-note{{in instantiation of template class 'struct BitfieldDivide<5, 0>' requested here}}
 }
+
+template<typename T, T I, int J>
+struct BitfieldDep {
+  int bitfield : I + J;
+};
+
+void test_BitfieldDep() {
+  (void)sizeof(BitfieldDep<int, 1, 5>);
+}
+