Skip to content

Commit baad4e7

Browse files
author
Sebastian Redl
committed
PODness and Type Traits
Make C++ classes track the POD property (C++ [class]p4) Track the existence of a copy assignment operator. Implicitly declare the copy assignment operator if none is provided. Implement most of the parsing job for the G++ type traits extension. Fully implement the low-hanging fruit of the type traits: __is_pod: Whether a type is a POD. __is_class: Whether a type is a (non-union) class. __is_union: Whether a type is a union. __is_enum: Whether a type is an enum. __is_polymorphic: Whether a type is polymorphic (C++ [class.virtual]p1). llvm-svn: 61746
1 parent 52e5dee commit baad4e7

22 files changed

+691
-26
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class CXXRecordDecl;
2222
class CXXConstructorDecl;
2323
class CXXDestructorDecl;
2424
class CXXConversionDecl;
25+
class CXXMethodDecl;
2526

2627
/// TemplateTypeParmDecl - Declaration of a template type parameter,
2728
/// e.g., "T" in
@@ -263,13 +264,20 @@ class CXXRecordDecl : public RecordDecl {
263264
/// user-declared copy constructor.
264265
bool UserDeclaredCopyConstructor : 1;
265266

267+
/// UserDeclaredCopyAssignment - True when this class has a
268+
/// user-declared copy assignment operator.
269+
bool UserDeclaredCopyAssignment : 1;
270+
266271
/// UserDeclaredDestructor - True when this class has a
267272
/// user-declared destructor.
268273
bool UserDeclaredDestructor : 1;
269274

270275
/// Aggregate - True when this class is an aggregate.
271276
bool Aggregate : 1;
272277

278+
/// PlainOldData - True when this class is a POD-type.
279+
bool PlainOldData : 1;
280+
273281
/// Polymorphic - True when this class is polymorphic, i.e. has at least one
274282
/// virtual member or derives from a polymorphic class.
275283
bool Polymorphic : 1;
@@ -321,6 +329,10 @@ class CXXRecordDecl : public RecordDecl {
321329
/// copy constructor that accepts a const-qualified argument.
322330
bool hasConstCopyConstructor(ASTContext &Context) const;
323331

332+
/// hasConstCopyAssignment - Determines whether this class has a
333+
/// copy assignment operator that accepts a const-qualified argument.
334+
bool hasConstCopyAssignment(ASTContext &Context) const;
335+
324336
/// addedConstructor - Notify the class that another constructor has
325337
/// been added. This routine helps maintain information about the
326338
/// class based on which constructors have been added.
@@ -338,6 +350,18 @@ class CXXRecordDecl : public RecordDecl {
338350
return UserDeclaredCopyConstructor;
339351
}
340352

353+
/// addedAssignmentOperator - Notify the class that another assignment
354+
/// operator has been added. This routine helps maintain information about the
355+
/// class based on which operators have been added.
356+
void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
357+
358+
/// hasUserDeclaredCopyAssignment - Whether this class has a
359+
/// user-declared copy assignment operator. When false, a copy
360+
/// assigment operator will be implicitly declared.
361+
bool hasUserDeclaredCopyAssignment() const {
362+
return UserDeclaredCopyAssignment;
363+
}
364+
341365
/// hasUserDeclaredDestructor - Whether this class has a
342366
/// user-declared destructor. When false, a destructor will be
343367
/// implicitly declared.
@@ -373,6 +397,15 @@ class CXXRecordDecl : public RecordDecl {
373397
/// [dcl.init.aggr]).
374398
void setAggregate(bool Agg) { Aggregate = Agg; }
375399

400+
/// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
401+
/// that is an aggregate that has no non-static non-POD data members, no
402+
/// reference data members, no user-defined copy assignment operator and no
403+
/// user-defined destructor.
404+
bool isPOD() const { return PlainOldData; }
405+
406+
/// setPOD - Set whether this class is a POD-type (C++ [class]p4).
407+
void setPOD(bool POD) { PlainOldData = POD; }
408+
376409
/// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]),
377410
/// which means that the class contains or inherits a virtual function.
378411
bool isPolymorphic() const { return Polymorphic; }

clang/include/clang/AST/ExprCXX.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_AST_EXPRCXX_H
1515
#define LLVM_CLANG_AST_EXPRCXX_H
1616

17+
#include "clang/Basic/TypeTraits.h"
1718
#include "clang/AST/Expr.h"
1819
#include "clang/AST/Decl.h"
1920

@@ -701,6 +702,51 @@ class CXXDependentNameExpr : public Expr {
701702
static CXXDependentNameExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
702703
};
703704

705+
/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the
706+
/// implementation of TR1/C++0x type trait templates.
707+
/// Example:
708+
/// __is_pod(int) == true
709+
/// __is_enum(std::string) == false
710+
class UnaryTypeTraitExpr : public Expr {
711+
/// UTT - The trait.
712+
UnaryTypeTrait UTT;
713+
714+
/// Loc - The location of the type trait keyword.
715+
SourceLocation Loc;
716+
717+
/// RParen - The location of the closing paren.
718+
SourceLocation RParen;
719+
720+
/// QueriedType - The type we're testing.
721+
QualType QueriedType;
722+
723+
public:
724+
UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, QualType queried,
725+
SourceLocation rparen, QualType ty)
726+
: Expr(UnaryTypeTraitExprClass, ty, false, queried->isDependentType()),
727+
UTT(utt), Loc(loc), RParen(rparen), QueriedType(queried) { }
728+
729+
virtual SourceRange getSourceRange() const { return SourceRange(Loc, RParen);}
730+
731+
UnaryTypeTrait getTrait() const { return UTT; }
732+
733+
QualType getQueriedType() const { return QueriedType; }
734+
735+
bool Evaluate() const;
736+
737+
static bool classof(const Stmt *T) {
738+
return T->getStmtClass() == UnaryTypeTraitExprClass;
739+
}
740+
static bool classof(const UnaryTypeTraitExpr *) { return true; }
741+
742+
// Iterators
743+
virtual child_iterator child_begin();
744+
virtual child_iterator child_end();
745+
746+
virtual void EmitImpl(llvm::Serializer& S) const;
747+
static UnaryTypeTraitExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
748+
};
749+
704750
} // end namespace clang
705751

706752
#endif

clang/include/clang/AST/StmtNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ STMT(CXXConditionDeclExpr , DeclRefExpr)
113113
STMT(CXXNewExpr , Expr)
114114
STMT(CXXDeleteExpr , Expr)
115115
STMT(CXXDependentNameExpr , Expr)
116+
STMT(UnaryTypeTraitExpr , Expr)
116117

117118
// Obj-C Expressions.
118119
STMT(ObjCStringLiteral , Expr)

clang/include/clang/AST/Type.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,10 @@ class Type {
295295
bool isIncompleteOrObjectType() const {
296296
return !isFunctionType();
297297
}
298-
298+
299+
/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10).
300+
bool isPODType() const;
301+
299302
/// isVariablyModifiedType (C99 6.7.5.2p2) - Return true for variable array
300303
/// types that have a non-constant expression. This does not include "[]".
301304
bool isVariablyModifiedType() const;

clang/include/clang/Basic/TokenKinds.def

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,25 @@ KEYWORD(__label__ , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
304304
KEYWORD(__real , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
305305
KEYWORD(__thread , EXTC90|EXTC99|EXTCPP|EXTCPP0x)
306306

307+
// GNU and MS Type Traits
308+
KEYWORD(__has_nothrow_assign , NOTC90|NOTC99)
309+
KEYWORD(__has_nothrow_copy , NOTC90|NOTC99)
310+
KEYWORD(__has_nothrow_constructor , NOTC90|NOTC99)
311+
KEYWORD(__has_trivial_assign , NOTC90|NOTC99)
312+
KEYWORD(__has_trivial_copy , NOTC90|NOTC99)
313+
KEYWORD(__has_trivial_constructor , NOTC90|NOTC99)
314+
KEYWORD(__has_trivial_destructor , NOTC90|NOTC99)
315+
KEYWORD(__has_virtual_destructor , NOTC90|NOTC99)
316+
KEYWORD(__is_abstract , NOTC90|NOTC99)
317+
KEYWORD(__is_base_of , NOTC90|NOTC99)
318+
KEYWORD(__is_class , NOTC90|NOTC99)
319+
KEYWORD(__is_empty , NOTC90|NOTC99)
320+
KEYWORD(__is_enum , NOTC90|NOTC99)
321+
KEYWORD(__is_pod , NOTC90|NOTC99)
322+
KEYWORD(__is_polymorphic , NOTC90|NOTC99)
323+
KEYWORD(__is_union , NOTC90|NOTC99)
324+
// FIXME: Add MS's traits, too.
325+
307326
// Apple Extension.
308327
KEYWORD(__private_extern__ , EXTC90|EXTC99|NOTCPP)
309328

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines enumerations for the type traits support.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_TYPETRAITS_H
15+
#define LLVM_CLANG_TYPETRAITS_H
16+
17+
namespace clang {
18+
19+
/// UnaryTypeTrait - Names for the unary type traits.
20+
enum UnaryTypeTrait {
21+
UTT_HasNothrowAssign,
22+
UTT_HasNothrowCopy,
23+
UTT_HasNothrowConstructor,
24+
UTT_HasTrivialAssign,
25+
UTT_HasTrivialCopy,
26+
UTT_HasTrivialConstructor,
27+
UTT_HasTrivialDestructor,
28+
UTT_HasVirtualDestructor,
29+
UTT_IsAbstract,
30+
UTT_IsClass,
31+
UTT_IsEmpty,
32+
UTT_IsEnum,
33+
UTT_IsPOD,
34+
UTT_IsPolymorphic,
35+
UTT_IsUnion
36+
};
37+
38+
}
39+
40+
#endif

clang/include/clang/Parse/Action.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/Basic/IdentifierTable.h"
1818
#include "clang/Basic/SourceLocation.h"
19+
#include "clang/Basic/TypeTraits.h"
1920
#include "clang/Parse/AccessSpecifier.h"
2021
#include "clang/Parse/Ownership.h"
2122

@@ -892,6 +893,14 @@ class Action : public ActionBase {
892893
return 0;
893894
}
894895

896+
virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
897+
SourceLocation KWLoc,
898+
SourceLocation LParen,
899+
TypeTy *Ty,
900+
SourceLocation RParen) {
901+
return ExprEmpty();
902+
}
903+
895904
//===---------------------------- C++ Classes ---------------------------===//
896905
/// ActOnBaseSpecifier - Parsed a base specifier
897906
virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl,

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,10 @@ class Parser {
984984
void AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS = 0);
985985
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
986986
OwningTemplateArgResult ParseTemplateArgument();
987-
987+
988+
//===--------------------------------------------------------------------===//
989+
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
990+
OwningExprResult ParseUnaryTypeTrait();
988991
};
989992

990993
} // end namespace clang

clang/lib/AST/DeclCXX.cpp

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC,
5656
SourceLocation L, IdentifierInfo *Id)
5757
: RecordDecl(CXXRecord, TK, DC, L, Id),
5858
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
59-
UserDeclaredDestructor(false), Aggregate(true), Polymorphic(false),
60-
Bases(0), NumBases(0),
61-
Conversions(DC, DeclarationName()) { }
59+
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
60+
Aggregate(true), PlainOldData(true), Polymorphic(false), Bases(0),
61+
NumBases(0), Conversions(DC, DeclarationName()) { }
6262

6363
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
6464
SourceLocation L, IdentifierInfo *Id,
@@ -91,7 +91,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
9191
}
9292

9393
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
94-
QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
94+
QualType ClassType
95+
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
9596
DeclarationName ConstructorName
9697
= Context.DeclarationNames.getCXXConstructorName(
9798
Context.getCanonicalType(ClassType));
@@ -107,7 +108,49 @@ bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
107108
return false;
108109
}
109110

110-
void
111+
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
112+
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
113+
const_cast<CXXRecordDecl*>(this)));
114+
DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal);
115+
116+
DeclContext::lookup_const_iterator Op, OpEnd;
117+
for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName);
118+
Op != OpEnd; ++Op) {
119+
// C++ [class.copy]p9:
120+
// A user-declared copy assignment operator is a non-static non-template
121+
// member function of class X with exactly one parameter of type X, X&,
122+
// const X&, volatile X& or const volatile X&.
123+
const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op);
124+
if (Method->isStatic())
125+
continue;
126+
// TODO: Skip templates? Or is this implicitly done due to parameter types?
127+
const FunctionTypeProto *FnType =
128+
Method->getType()->getAsFunctionTypeProto();
129+
assert(FnType && "Overloaded operator has no prototype.");
130+
// Don't assert on this; an invalid decl might have been left in the AST.
131+
if (FnType->getNumArgs() != 1 || FnType->isVariadic())
132+
continue;
133+
bool AcceptsConst = true;
134+
QualType ArgType = FnType->getArgType(0);
135+
if (const ReferenceType *Ref = ArgType->getAsReferenceType()) {
136+
ArgType = Ref->getPointeeType();
137+
// Is it a non-const reference?
138+
if (!ArgType.isConstQualified())
139+
AcceptsConst = false;
140+
}
141+
if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
142+
continue;
143+
144+
// We have a single argument of type cv X or cv X&, i.e. we've found the
145+
// copy assignment operator. Return whether it accepts const arguments.
146+
return AcceptsConst;
147+
}
148+
assert(isInvalidDecl() &&
149+
"No copy assignment operator declared in valid code.");
150+
return false;
151+
}
152+
153+
void
111154
CXXRecordDecl::addedConstructor(ASTContext &Context,
112155
CXXConstructorDecl *ConDecl) {
113156
if (!ConDecl->isImplicitlyDeclared()) {
@@ -119,13 +162,46 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
119162
// user-declared constructors (12.1) [...].
120163
Aggregate = false;
121164

165+
// C++ [class]p4:
166+
// A POD-struct is an aggregate class [...]
167+
PlainOldData = false;
168+
122169
// Note when we have a user-declared copy constructor, which will
123170
// suppress the implicit declaration of a copy constructor.
124171
if (ConDecl->isCopyConstructor(Context))
125172
UserDeclaredCopyConstructor = true;
126173
}
127174
}
128175

176+
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
177+
CXXMethodDecl *OpDecl) {
178+
// We're interested specifically in copy assignment operators.
179+
// Unlike addedConstructor, this method is not called for implicit
180+
// declarations.
181+
const FunctionTypeProto *FnType = OpDecl->getType()->getAsFunctionTypeProto();
182+
assert(FnType && "Overloaded operator has no proto function type.");
183+
assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
184+
QualType ArgType = FnType->getArgType(0);
185+
if (const ReferenceType *Ref = ArgType->getAsReferenceType())
186+
ArgType = Ref->getPointeeType();
187+
188+
ArgType = ArgType.getUnqualifiedType();
189+
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
190+
const_cast<CXXRecordDecl*>(this)));
191+
192+
if (ClassType != Context.getCanonicalType(ArgType))
193+
return;
194+
195+
// This is a copy assignment operator.
196+
// Suppress the implicit declaration of a copy constructor.
197+
UserDeclaredCopyAssignment = true;
198+
199+
// C++ [class]p4:
200+
// A POD-struct is an aggregate class that [...] has no user-defined copy
201+
// assignment operator [...].
202+
PlainOldData = false;
203+
}
204+
129205
void CXXRecordDecl::addConversionFunction(ASTContext &Context,
130206
CXXConversionDecl *ConvDecl) {
131207
Conversions.addOverload(ConvDecl);

clang/lib/AST/Expr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,10 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
10921092
case CXXDefaultArgExprClass:
10931093
return cast<CXXDefaultArgExpr>(this)
10941094
->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
1095+
1096+
case UnaryTypeTraitExprClass:
1097+
Result = cast<UnaryTypeTraitExpr>(this)->Evaluate();
1098+
return true;
10951099
}
10961100

10971101
// Cases that are valid constant exprs fall through to here.

0 commit comments

Comments
 (0)