Add proper type-source information to UnaryTypeTraitExpr, including

libclang visitation.

llvm-svn: 113492
This commit is contained in:
Douglas Gregor 2010-09-09 16:14:44 +00:00
parent db0ddaa50b
commit 54e5b13a27
11 changed files with 90 additions and 63 deletions

View File

@ -1378,24 +1378,28 @@ class UnaryTypeTraitExpr : public Expr {
/// RParen - The location of the closing paren.
SourceLocation RParen;
/// QueriedType - The type we're testing.
QualType QueriedType;
TypeSourceInfo *QueriedType;
public:
UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried,
UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt,
TypeSourceInfo *queried,
SourceLocation rparen, QualType ty)
: Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()),
: Expr(UnaryTypeTraitExprClass, ty, false,
queried->getType()->isDependentType()),
UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { }
explicit UnaryTypeTraitExpr(EmptyShell Empty)
: Expr(UnaryTypeTraitExprClass, Empty), UTT((UnaryTypeTrait)0) { }
: Expr(UnaryTypeTraitExprClass, Empty), UTT((UnaryTypeTrait)0),
QueriedType() { }
virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
UnaryTypeTrait getTrait() const { return UTT; }
QualType getQueriedType() const { return QueriedType; }
QualType getQueriedType() const { return QueriedType->getType(); }
TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; }
bool EvaluateTrait(ASTContext&) const;
static bool classof(const Stmt *T) {

View File

@ -1782,7 +1782,7 @@ DEF_TRAVERSE_STMT(TypesCompatibleExpr, {
})
DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, {
TRY_TO(TraverseType(S->getQueriedType()));
TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc()));
})
// These exprs (most of them), do not need any action except iterating

View File

@ -2260,10 +2260,14 @@ public:
/// pseudo-functions.
ExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation KWLoc,
SourceLocation LParen,
ParsedType Ty,
SourceLocation RParen);
ExprResult BuildUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation KWLoc,
TypeSourceInfo *T,
SourceLocation RParen);
ExprResult ActOnStartCXXMemberReference(Scope *S,
Expr *Base,
SourceLocation OpLoc,

View File

@ -328,30 +328,31 @@ StmtIterator DependentScopeDeclRefExpr::child_end() {
}
bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
QualType T = getQueriedType();
switch(UTT) {
default: assert(false && "Unknown type trait or not implemented");
case UTT_IsPOD: return QueriedType->isPODType();
case UTT_IsLiteral: return QueriedType->isLiteralType();
case UTT_IsPOD: return T->isPODType();
case UTT_IsLiteral: return T->isLiteralType();
case UTT_IsClass: // Fallthrough
case UTT_IsUnion:
if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
if (const RecordType *Record = T->getAs<RecordType>()) {
bool Union = Record->getDecl()->isUnion();
return UTT == UTT_IsUnion ? Union : !Union;
}
return false;
case UTT_IsEnum: return QueriedType->isEnumeralType();
case UTT_IsEnum: return T->isEnumeralType();
case UTT_IsPolymorphic:
if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
if (const RecordType *Record = T->getAs<RecordType>()) {
// Type traits are only parsed in C++, so we've got CXXRecords.
return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic();
}
return false;
case UTT_IsAbstract:
if (const RecordType *RT = QueriedType->getAs<RecordType>())
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
return false;
case UTT_IsEmpty:
if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
if (const RecordType *Record = T->getAs<RecordType>()) {
return !Record->getDecl()->isUnion()
&& cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
}
@ -361,10 +362,10 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
// constructor ([class.ctor]) then the trait is true, else it is false.
if (QueriedType->isPODType())
if (T->isPODType())
return true;
if (const RecordType *RT =
C.getBaseElementType(QueriedType)->getAs<RecordType>())
C.getBaseElementType(T)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
return false;
case UTT_HasTrivialCopy:
@ -373,9 +374,9 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// the trait is true, else if type is a cv class or union type
// with a trivial copy constructor ([class.copy]) then the trait
// is true, else it is false.
if (QueriedType->isPODType() || QueriedType->isReferenceType())
if (T->isPODType() || T->isReferenceType())
return true;
if (const RecordType *RT = QueriedType->getAs<RecordType>())
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
return false;
case UTT_HasTrivialAssign:
@ -391,11 +392,11 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// errors if the copy assignment operator is actually used, q.v.
// [class.copy]p12).
if (C.getBaseElementType(QueriedType).isConstQualified())
if (C.getBaseElementType(T).isConstQualified())
return false;
if (QueriedType->isPODType())
if (T->isPODType())
return true;
if (const RecordType *RT = QueriedType->getAs<RecordType>())
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
return false;
case UTT_HasTrivialDestructor:
@ -405,10 +406,10 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// type (or array thereof) with a trivial destructor
// ([class.dtor]) then the trait is true, else it is
// false.
if (QueriedType->isPODType() || QueriedType->isReferenceType())
if (T->isPODType() || T->isReferenceType())
return true;
if (const RecordType *RT =
C.getBaseElementType(QueriedType)->getAs<RecordType>())
C.getBaseElementType(T)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
return false;
// TODO: Propagate nothrowness for implicitly declared special members.
@ -420,13 +421,13 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// or union type with copy assignment operators that are known
// not to throw an exception then the trait is true, else it is
// false.
if (C.getBaseElementType(QueriedType).isConstQualified())
if (C.getBaseElementType(T).isConstQualified())
return false;
if (QueriedType->isReferenceType())
if (T->isReferenceType())
return false;
if (QueriedType->isPODType())
if (T->isPODType())
return true;
if (const RecordType *RT = QueriedType->getAs<RecordType>()) {
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyAssignment())
return true;
@ -458,9 +459,9 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// if type is a cv class or union type with copy constructors that are
// known not to throw an exception then the trait is true, else it is
// false.
if (QueriedType->isPODType() || QueriedType->isReferenceType())
if (T->isPODType() || T->isReferenceType())
return true;
if (const RecordType *RT = QueriedType->getAs<RecordType>()) {
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyConstructor())
return true;
@ -469,8 +470,7 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
bool AllNoThrow = true;
unsigned FoundTQs;
DeclarationName ConstructorName
= C.DeclarationNames.getCXXConstructorName(
C.getCanonicalType(QueriedType));
= C.DeclarationNames.getCXXConstructorName(C.getCanonicalType(T));
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = RD->lookup(ConstructorName);
Con != ConEnd; ++Con) {
@ -495,10 +495,9 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// true, else if type is a cv class or union type (or array
// thereof) with a default constructor that is known not to
// throw an exception then the trait is true, else it is false.
if (QueriedType->isPODType())
if (T->isPODType())
return true;
if (const RecordType *RT =
C.getBaseElementType(QueriedType)->getAs<RecordType>()) {
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialConstructor())
return true;
@ -517,7 +516,7 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If type is a class type with a virtual destructor ([class.dtor])
// then the trait is true, else it is false.
if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
if (const RecordType *Record = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (CXXDestructorDecl *Destructor = RD->getDestructor())
return Destructor->isVirtual();

View File

@ -1832,7 +1832,7 @@ ExprResult Parser::ParseUnaryTypeTrait() {
if (Ty.isInvalid())
return ExprError();
return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
return Actions.ActOnUnaryTypeTrait(UTT, Loc, Ty.get(), RParen);
}
/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a

View File

@ -1982,12 +1982,23 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
}
ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation KWLoc,
SourceLocation LParen,
ParsedType Ty,
SourceLocation RParen) {
QualType T = GetTypeFromParser(Ty);
SourceLocation KWLoc,
ParsedType Ty,
SourceLocation RParen) {
TypeSourceInfo *TSInfo;
QualType T = GetTypeFromParser(Ty, &TSInfo);
if (!TSInfo)
TSInfo = Context.getTrivialTypeSourceInfo(T);
return BuildUnaryTypeTrait(OTT, KWLoc, TSInfo, RParen);
}
ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait OTT,
SourceLocation KWLoc,
TypeSourceInfo *TSInfo,
SourceLocation RParen) {
QualType T = TSInfo->getType();
// According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html
// all traits except __is_class, __is_enum and __is_union require a the type
// to be complete, an array of unknown bound, or void.
@ -2004,7 +2015,7 @@ ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
// There is no point in eagerly computing the value. The traits are designed
// to be used from type trait templates, so Ty will be a template parameter
// 99% of the time.
return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, T,
return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, TSInfo,
RParen, Context.BoolTy));
}

View File

@ -1643,12 +1643,10 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildUnaryTypeTrait(UnaryTypeTrait Trait,
SourceLocation StartLoc,
SourceLocation LParenLoc,
QualType T,
SourceLocation RParenLoc) {
return getSema().ActOnUnaryTypeTrait(Trait, StartLoc, LParenLoc,
ParsedType::make(T), RParenLoc);
SourceLocation StartLoc,
TypeSourceInfo *T,
SourceLocation RParenLoc) {
return getSema().BuildUnaryTypeTrait(Trait, StartLoc, T, RParenLoc);
}
/// \brief Build a new (previously unresolved) declaration reference
@ -5614,23 +5612,16 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
QualType T = getDerived().TransformType(E->getQueriedType());
if (T.isNull())
TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
if (!T)
return ExprError();
if (!getDerived().AlwaysRebuild() &&
T == E->getQueriedType())
T == E->getQueriedTypeSourceInfo())
return SemaRef.Owned(E->Retain());
// FIXME: Bad location information
SourceLocation FakeLParenLoc
= SemaRef.PP.getLocForEndOfToken(E->getLocStart());
return getDerived().RebuildUnaryTypeTrait(E->getTrait(),
E->getLocStart(),
/*FIXME:*/FakeLParenLoc,
T,
E->getLocEnd());
}

View File

@ -1249,7 +1249,7 @@ void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
SourceRange Range = Reader.ReadSourceRange(Record, Idx);
E->Loc = Range.getBegin();
E->RParen = Range.getEnd();
E->QueriedType = Reader.GetType(Record[Idx++]);
E->QueriedType = Reader.GetTypeSourceInfo(DeclsCursor, Record, Idx);
}
Stmt *ASTReader::ReadStmt(llvm::BitstreamCursor &Cursor) {

View File

@ -1279,7 +1279,7 @@ void ASTStmtWriter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
VisitExpr(E);
Record.push_back(E->getTrait());
Writer.AddSourceRange(E->getSourceRange(), Record);
Writer.AddTypeRef(E->getQueriedType(), Record);
Writer.AddTypeSourceInfo(E->getQueriedTypeSourceInfo(), Record);
Code = serialization::EXPR_CXX_UNARY_TYPE_TRAIT;
}

View File

@ -88,6 +88,7 @@ template<typename T>
void test_even_more_dependent_exprs(T t, Y y) {
typedef T type;
(void)type(t, y);
(void)__has_nothrow_assign(type);
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
@ -195,3 +196,5 @@ void test_even_more_dependent_exprs(T t, Y y) {
// CHECK: load-stmts.cpp:90:9: TypeRef=type:89:13 Extent=[90:9 - 90:13]
// CHECK: load-stmts.cpp:90:14: DeclRefExpr=t:88:39 Extent=[90:14 - 90:15]
// CHECK: load-stmts.cpp:90:17: DeclRefExpr=y:88:44 Extent=[90:17 - 90:18]
// CHECK: load-stmts.cpp:91:9: UnexposedExpr= Extent=[91:9 - 91:35]
// CHECK: load-stmts.cpp:91:30: TypeRef=type:89:13 Extent=[91:30 - 91:34]

View File

@ -366,7 +366,6 @@ public:
bool VisitCaseStmt(CaseStmt *S);
bool VisitWhileStmt(WhileStmt *S);
bool VisitForStmt(ForStmt *S);
// bool VisitSwitchCase(SwitchCase *S);
// Expression visitors
bool VisitDeclRefExpr(DeclRefExpr *E);
@ -385,12 +384,13 @@ public:
// FIXME: InitListExpr (for the designators)
// FIXME: DesignatedInitExpr
bool VisitCXXTypeidExpr(CXXTypeidExpr *E);
bool VisitCXXUuidofExpr(CXXUuidofExpr *E);
bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { return false; }
bool VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
bool VisitCXXNewExpr(CXXNewExpr *E);
bool VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
// FIXME: UnaryTypeTraitExpr has poor source-location information.
bool VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
bool VisitOverloadExpr(OverloadExpr *E);
bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
bool VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
@ -1590,6 +1590,17 @@ bool CursorVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
return VisitExpr(E);
}
bool CursorVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
if (E->isTypeOperand()) {
if (TypeSourceInfo *TSInfo = E->getTypeOperandSourceInfo())
return Visit(TSInfo->getTypeLoc());
return false;
}
return VisitExpr(E);
}
bool CursorVisitor::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
if (TypeSourceInfo *TSInfo = E->getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
@ -1651,6 +1662,10 @@ bool CursorVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
return false;
}
bool CursorVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
return Visit(E->getQueriedTypeSourceInfo()->getTypeLoc());
}
bool CursorVisitor::VisitOverloadExpr(OverloadExpr *E) {
// Visit the nested-name-specifier.
if (NestedNameSpecifier *Qualifier = E->getQualifier())