[cfe-commits] r102393 - in /cfe/trunk: 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 test/SemaCXX/typeid.cpp

Douglas Gregor dgregor at apple.com
Mon Apr 26 15:37:10 PDT 2010


Author: dgregor
Date: Mon Apr 26 17:37:10 2010
New Revision: 102393

URL: http://llvm.org/viewvc/llvm-project?rev=102393&view=rev
Log:
Improve source-location information in a C++ typeid (type) expression
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.

Added:
    cfe/trunk/test/SemaCXX/typeid-ref.cpp
Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaCXX/typeid.cpp

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Mon Apr 26 17:37:10 2010
@@ -298,37 +298,41 @@
 /// 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 {

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Mon Apr 26 17:37:10 2010
@@ -18,16 +18,25 @@
 #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

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Apr 26 17:37:10 2010
@@ -2192,6 +2192,15 @@
                                      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,

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Apr 26 17:37:10 2010
@@ -273,89 +273,107 @@
   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.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Apr 26 17:37:10 2010
@@ -1499,30 +1499,24 @@
   ///
   /// 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 @@
 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 @@
       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());
 }

Added: cfe/trunk/test/SemaCXX/typeid-ref.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typeid-ref.cpp?rev=102393&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/typeid-ref.cpp (added)
+++ cfe/trunk/test/SemaCXX/typeid-ref.cpp Mon Apr 26 17:37:10 2010
@@ -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&);
+}

Modified: cfe/trunk/test/SemaCXX/typeid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typeid.cpp?rev=102393&r1=102392&r2=102393&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/typeid.cpp (original)
+++ cfe/trunk/test/SemaCXX/typeid.cpp Mon Apr 26 17:37:10 2010
@@ -5,7 +5,6 @@
   (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;
 }





More information about the cfe-commits mailing list