]> granicus.if.org Git - clang/commitdiff
Improve source-location information in a C++ typeid (type) expression
authorDouglas Gregor <dgregor@apple.com>
Mon, 26 Apr 2010 22:37:10 +0000 (22:37 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 26 Apr 2010 22:37:10 +0000 (22:37 +0000)
by using TypeSourceInfo, cleaning up the representation
somewhat. Teach getTypeOperand() to strip references and
cv-qualifiers, providing the semantic view of the type without
requiring any extra storage (the unmodified type remains within the
TypeSourceInfo). This fixes a bug found by Boost's call_traits test.

Finally, clean up semantic analysis, by splitting the ActOnCXXTypeid
routine into ActOnCXXTypeId (the parser action) and two BuildCXXTypeId
functions, which perform the semantic analysis for typeid(type) and
typeid(expression), respectively. We now perform less work at template
instantiation time (we don't look for std::type_info again) and can
give better diagnostics.

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

include/clang/AST/ExprCXX.h
lib/AST/ExprCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/typeid-ref.cpp [new file with mode: 0644]
test/SemaCXX/typeid.cpp

index fe6fdb7c351e9d7598dce99451d95f2ea7298513..d66642c1ad61fe5e3a7f6bd8da25a355aa045d8a 100644 (file)
@@ -298,37 +298,41 @@ public:
 /// This represents code like @c typeid(int) or @c typeid(*objPtr)
 class CXXTypeidExpr : public Expr {
 private:
-  bool isTypeOp : 1;
-  union {
-    void *Ty;
-    Stmt *Ex;
-  } Operand;
+  llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand;
   SourceRange Range;
 
 public:
-  CXXTypeidExpr(bool isTypeOp, void *op, QualType Ty, const SourceRange r) :
-      Expr(CXXTypeidExprClass, Ty,
+  CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R)
+    : Expr(CXXTypeidExprClass, Ty, 
+           // typeid is never type-dependent (C++ [temp.dep.expr]p4)
+           false,
+           // typeid is value-dependent if the type or expression are dependent
+           Operand->getType()->isDependentType()),
+      Operand(Operand), Range(R) { }
+  
+  CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R)
+    : Expr(CXXTypeidExprClass, Ty,
         // typeid is never type-dependent (C++ [temp.dep.expr]p4)
         false,
         // typeid is value-dependent if the type or expression are dependent
-        (isTypeOp ? QualType::getFromOpaquePtr(op)->isDependentType()
-                  : static_cast<Expr*>(op)->isValueDependent())),
-      isTypeOp(isTypeOp), Range(r) {
-    if (isTypeOp)
-      Operand.Ty = op;
-    else
-      // op was an Expr*, so cast it back to that to be safe
-      Operand.Ex = static_cast<Expr*>(op);
-  }
+        Operand->isTypeDependent() || Operand->isValueDependent()),
+      Operand(Operand), Range(R) { }
 
-  bool isTypeOperand() const { return isTypeOp; }
-  QualType getTypeOperand() const {
+  bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); }
+  
+  /// \brief Retrieves the type operand of this typeid() expression after
+  /// various required adjustments (removing reference types, cv-qualifiers).
+  QualType getTypeOperand() const;
+
+  /// \brief Retrieve source information for the type operand.
+  TypeSourceInfo *getTypeOperandSourceInfo() const {
     assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
-    return QualType::getFromOpaquePtr(Operand.Ty);
+    return Operand.get<TypeSourceInfo *>();
   }
+  
   Expr* getExprOperand() const {
     assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)");
-    return static_cast<Expr*>(Operand.Ex);
+    return static_cast<Expr*>(Operand.get<Stmt *>());
   }
 
   virtual SourceRange getSourceRange() const {
index c19fd834eae88db70da68a617b3034e9d93ad8dc..5f908096bbb0ccd16f318e7f266ff55c0f899fc1 100644 (file)
 #include "clang/AST/TypeLoc.h"
 using namespace clang;
 
+
 //===----------------------------------------------------------------------===//
 //  Child Iterators for iterating over subexpressions/substatements
 //===----------------------------------------------------------------------===//
 
+QualType CXXTypeidExpr::getTypeOperand() const {
+  assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
+  return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
+                                                        .getUnqualifiedType();
+}
+
 // CXXTypeidExpr - has child iterators if the operand is an expression
 Stmt::child_iterator CXXTypeidExpr::child_begin() {
-  return isTypeOperand() ? child_iterator() : &Operand.Ex;
+  return isTypeOperand() ? child_iterator() 
+                         : reinterpret_cast<Stmt **>(&Operand);
 }
 Stmt::child_iterator CXXTypeidExpr::child_end() {
-  return isTypeOperand() ? child_iterator() : &Operand.Ex+1;
+  return isTypeOperand() ? child_iterator() 
+                         : reinterpret_cast<Stmt **>(&Operand) + 1;
 }
 
 // CXXBoolLiteralExpr
index 5eb95714dcdbff95e050c0a13ccf424f408b6891..3ea9bd0afa0adbd4fbf683f63c4b7e56a99d959d 100644 (file)
@@ -2192,6 +2192,15 @@ public:
                                      SourceRange AngleBrackets,
                                      SourceRange Parens);
 
+  OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+                                  SourceLocation TypeidLoc,
+                                  TypeSourceInfo *Operand,
+                                  SourceLocation RParenLoc);
+  OwningExprResult BuildCXXTypeId(QualType TypeInfoType,
+                                  SourceLocation TypeidLoc,
+                                  ExprArg Operand,
+                                  SourceLocation RParenLoc);
+  
   /// ActOnCXXTypeid - Parse typeid( something ).
   virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
                                           SourceLocation LParenLoc, bool isType,
index 84466e1d3e32076d5071795c3d9614c7603a448d..7c324235ca838d0d30c0d29c13b268bfbbcdd715 100644 (file)
@@ -273,89 +273,107 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
   return 0;
 }
 
-/// ActOnCXXTypeidOfType - Parse typeid( type-id ).
+/// \brief Build a C++ typeid expression with a type operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+                                            SourceLocation TypeidLoc,
+                                            TypeSourceInfo *Operand,
+                                            SourceLocation RParenLoc) {
+  // C++ [expr.typeid]p4:
+  //   The top-level cv-qualifiers of the lvalue expression or the type-id 
+  //   that is the operand of typeid are always ignored.
+  //   If the type of the type-id is a class type or a reference to a class 
+  //   type, the class shall be completely-defined.
+  QualType T = Operand->getType().getNonReferenceType();
+  if (T->getAs<RecordType>() &&
+      RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
+    return ExprError();
+  
+  return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+                                           Operand,
+                                           SourceRange(TypeidLoc, RParenLoc)));
+}
+
+/// \brief Build a C++ typeid expression with an expression operand.
+Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
+                                            SourceLocation TypeidLoc,
+                                            ExprArg Operand,
+                                            SourceLocation RParenLoc) {
+  bool isUnevaluatedOperand = true;
+  Expr *E = static_cast<Expr *>(Operand.get());
+  if (E && !E->isTypeDependent()) {
+    QualType T = E->getType();
+    if (const RecordType *RecordT = T->getAs<RecordType>()) {
+      CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
+      // C++ [expr.typeid]p3:
+      //   [...] If the type of the expression is a class type, the class
+      //   shall be completely-defined.
+      if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid))
+        return ExprError();
+      
+      // C++ [expr.typeid]p3:
+      //   When typeid is applied to an expression other than an lvalue of a
+      //   polymorphic class type [...] [the] expression is an unevaluated
+      //   operand. [...]
+      if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
+        isUnevaluatedOperand = false;
+    }
+    
+    // C++ [expr.typeid]p4:
+    //   [...] If the type of the type-id is a reference to a possibly
+    //   cv-qualified type, the result of the typeid expression refers to a 
+    //   std::type_info object representing the cv-unqualified referenced 
+    //   type.
+    if (T.hasQualifiers()) {
+      ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
+                        E->isLvalue(Context));
+      Operand.release();
+      Operand = Owned(E);
+    }
+  }
+  
+  // If this is an unevaluated operand, clear out the set of
+  // declaration references we have been computing and eliminate any
+  // temporaries introduced in its computation.
+  if (isUnevaluatedOperand)
+    ExprEvalContexts.back().Context = Unevaluated;
+  
+  return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(),
+                                           Operand.takeAs<Expr>(),
+                                           SourceRange(TypeidLoc, RParenLoc)));  
+}
+
+/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression);
 Action::OwningExprResult
 Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
                      bool isType, void *TyOrExpr, SourceLocation RParenLoc) {
+  // Find the std::type_info type.
   if (!StdNamespace)
     return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
 
-  if (isType) {
-    // C++ [expr.typeid]p4:
-    //   The top-level cv-qualifiers of the lvalue expression or the type-id 
-    //   that is the operand of typeid are always ignored.
-    // FIXME: Preserve type source info.
-    // FIXME: Preserve the type before we stripped the cv-qualifiers?
-    QualType T = GetTypeFromParser(TyOrExpr);
-    if (T.isNull())
-      return ExprError();
-    
-    // C++ [expr.typeid]p4:
-    //   If the type of the type-id is a class type or a reference to a class 
-    //   type, the class shall be completely-defined.
-    QualType CheckT = T;
-    if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>())
-      CheckT = RefType->getPointeeType();
-    
-    if (CheckT->getAs<RecordType>() &&
-        RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid))
-      return ExprError();
-    
-    TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr();
-  }
-
   IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
   LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName);
   LookupQualifiedName(R, StdNamespace);
   RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>();
   if (!TypeInfoRecordDecl)
     return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid));
-
+  
   QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
+  
+  if (isType) {
+    // The operand is a type; handle it as such.
+    TypeSourceInfo *TInfo = 0;
+    QualType T = GetTypeFromParser(TyOrExpr, &TInfo);
+    if (T.isNull())
+      return ExprError();
+    
+    if (!TInfo)
+      TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc);
 
-  if (!isType) {
-    bool isUnevaluatedOperand = true;
-    Expr *E = static_cast<Expr *>(TyOrExpr);
-    if (E && !E->isTypeDependent()) {
-      QualType T = E->getType();
-      if (const RecordType *RecordT = T->getAs<RecordType>()) {
-        CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
-        // C++ [expr.typeid]p3:
-        //   [...] If the type of the expression is a class type, the class
-        //   shall be completely-defined.
-        if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid))
-          return ExprError();
-
-        // C++ [expr.typeid]p3:
-        //   When typeid is applied to an expression other than an lvalue of a
-        //   polymorphic class type [...] [the] expression is an unevaluated
-        //   operand. [...]
-        if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid)
-          isUnevaluatedOperand = false;
-      }
-
-      // C++ [expr.typeid]p4:
-      //   [...] If the type of the type-id is a reference to a possibly
-      //   cv-qualified type, the result of the typeid expression refers to a 
-      //   std::type_info object representing the cv-unqualified referenced 
-      //   type.
-      if (T.hasQualifiers()) {
-        ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp,
-                          E->isLvalue(Context));
-        TyOrExpr = E;
-      }
-    }
-
-    // If this is an unevaluated operand, clear out the set of
-    // declaration references we have been computing and eliminate any
-    // temporaries introduced in its computation.
-    if (isUnevaluatedOperand)
-      ExprEvalContexts.back().Context = Unevaluated;
+    return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc);
   }
 
-  return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
-                                           TypeInfoType.withConst(),
-                                           SourceRange(OpLoc, RParenLoc)));
+  // The operand is an expression.  
+  return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc);
 }
 
 /// ActOnCXXBoolLiteral - Parse {true,false} literals.
index cded16cd60dccfd8a8ded0183adc9cda6dd8e974..f80747b69f10491f599daaefe26eba19e0045124 100644 (file)
@@ -1499,30 +1499,24 @@ public:
   ///
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
-  OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
-                                        SourceLocation LParenLoc,
-                                        QualType T,
+  OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+                                        SourceLocation TypeidLoc,
+                                        TypeSourceInfo *Operand,
                                         SourceLocation RParenLoc) {
-    return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true,
-                                    T.getAsOpaquePtr(), RParenLoc);
+    return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand, 
+                                    RParenLoc);
   }
 
   /// \brief Build a new C++ typeid(expr) expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
-  OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc,
-                                        SourceLocation LParenLoc,
+  OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType,
+                                        SourceLocation TypeidLoc,
                                         ExprArg Operand,
                                         SourceLocation RParenLoc) {
-    OwningExprResult Result
-      = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(),
-                                 RParenLoc);
-    if (Result.isInvalid())
-      return getSema().ExprError();
-
-    Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership
-    return move(Result);
+    return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, move(Operand),
+                                    RParenLoc);
   }
 
   /// \brief Build a new C++ "this" expression.
@@ -4943,19 +4937,18 @@ template<typename Derived>
 Sema::OwningExprResult
 TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
   if (E->isTypeOperand()) {
-    TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
-
-    QualType T = getDerived().TransformType(E->getTypeOperand());
-    if (T.isNull())
+    TypeSourceInfo *TInfo
+      = getDerived().TransformType(E->getTypeOperandSourceInfo());
+    if (!TInfo)
       return SemaRef.ExprError();
 
     if (!getDerived().AlwaysRebuild() &&
-        T == E->getTypeOperand())
+        TInfo == E->getTypeOperandSourceInfo())
       return SemaRef.Owned(E->Retain());
 
-    return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
-                                             /*FIXME:*/E->getLocStart(),
-                                             T,
+    return getDerived().RebuildCXXTypeidExpr(E->getType(),
+                                             E->getLocStart(),
+                                             TInfo,
                                              E->getLocEnd());
   }
 
@@ -4973,8 +4966,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) {
       SubExpr.get() == E->getExprOperand())
     return SemaRef.Owned(E->Retain());
 
-  return getDerived().RebuildCXXTypeidExpr(E->getLocStart(),
-                                           /*FIXME:*/E->getLocStart(),
+  return getDerived().RebuildCXXTypeidExpr(E->getType(),
+                                           E->getLocStart(),
                                            move(SubExpr),
                                            E->getLocEnd());
 }
diff --git a/test/SemaCXX/typeid-ref.cpp b/test/SemaCXX/typeid-ref.cpp
new file mode 100644 (file)
index 0000000..da00169
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+namespace std {
+  class type_info;
+}
+
+struct X { };
+
+void f() {
+  // CHECK: @_ZTS1X = weak_odr constant
+  // CHECK: @_ZTI1X = weak_odr constant 
+  (void)typeid(X&);
+}
index 0e78ff46a65c69c3681cf7378edff6c0bc02950b..8db7db507464a68cc089768b0e164e78aa19747c 100644 (file)
@@ -5,7 +5,6 @@ void f()
   (void)typeid(int); // expected-error {{error: you need to include <typeinfo> before using the 'typeid' operator}}
 }
 
-// FIXME: This should really include <typeinfo>, but we don't have that yet.
 namespace std {
   class type_info;
 }