/// 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 {
#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
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,
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.
///
/// 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.
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());
}
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());
}
--- /dev/null
+// 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&);
+}
(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;
}