/// 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) {
})
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
/// 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,
}
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();
}
// 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:
// 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:
// 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:
// 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.
// 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;
// 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;
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) {
// 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;
// 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();
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
}
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.
// 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));
}
/// 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
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());
}
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) {
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;
}
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
// 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]
bool VisitCaseStmt(CaseStmt *S);
bool VisitWhileStmt(WhileStmt *S);
bool VisitForStmt(ForStmt *S);
-// bool VisitSwitchCase(SwitchCase *S);
// Expression visitors
bool VisitDeclRefExpr(DeclRefExpr *E);
// 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);
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());
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())