diff options
-rw-r--r-- | AST/ASTContext.cpp | 12 | ||||
-rw-r--r-- | AST/Type.cpp | 12 | ||||
-rw-r--r-- | Parse/DeclSpec.cpp | 2 | ||||
-rw-r--r-- | Parse/ParseDecl.cpp | 48 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 2 | ||||
-rw-r--r-- | Sema/SemaType.cpp | 12 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 2 | ||||
-rw-r--r-- | include/clang/AST/ASTContext.h | 4 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 34 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 4 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 1 | ||||
-rw-r--r-- | test/Parser/typeof.c | 18 |
12 files changed, 147 insertions, 4 deletions
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index a9fb81faad..6f7165101e 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -584,6 +584,18 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +QualType ASTContext::getTypeOfType(Expr *tofExpr) { + QualType Canonical = tofExpr->getType().getCanonicalType(); + // Note: TypeOfExpr's aren't uniqued. + return QualType(new TypeOfExpr(tofExpr, Canonical), 0); +} + +QualType ASTContext::getTypeOfType(QualType tofType) { + QualType Canonical = tofType.getCanonicalType(); + // Note: TypeOfType's aren't uniqued. + return QualType(new TypeOfType(tofType, Canonical), 0); +} + /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. QualType ASTContext::getTagDeclType(TagDecl *Decl) { diff --git a/AST/Type.cpp b/AST/Type.cpp index 214dbea488..ecade56706 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -638,6 +638,18 @@ void OCUVectorType::getAsStringInternal(std::string &S) const { ElementType.getAsStringInternal(S); } +void TypeOfExpr::getAsStringInternal(std::string &InnerString) const { + // FIXME: output expression, getUnderlyingExpr()->print(). + // At the moment, Stmt::print(std::ostream) doesn't work for us here. + InnerString = "typeof(<expr>) " + InnerString; +} + +void TypeOfType::getAsStringInternal(std::string &S) const { + std::string Tmp; + getUnderlyingType().getAsStringInternal(Tmp); + S += "typeof(" + Tmp + ")"; +} + void FunctionTypeNoProto::getAsStringInternal(std::string &S) const { // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) diff --git a/Parse/DeclSpec.cpp b/Parse/DeclSpec.cpp index d3ddf47a83..31338d81df 100644 --- a/Parse/DeclSpec.cpp +++ b/Parse/DeclSpec.cpp @@ -98,6 +98,8 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_union: return "union"; case DeclSpec::TST_struct: return "struct"; case DeclSpec::TST_typedef: return "typedef"; + case DeclSpec::TST_typeofType: + case DeclSpec::TST_typeofExpr: return "typeof"; } } diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index b05fd7898d..6b5215b90c 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -482,6 +482,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { ParseEnumSpecifier(DS); continue; + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + continue; + // type-qualifier case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, @@ -825,6 +830,9 @@ bool Parser::isTypeSpecifierQualifier() const { default: return false; // GNU attributes support. case tok::kw___attribute: + // GNU typeof support. + case tok::kw_typeof: + // type-specifiers case tok::kw_short: case tok::kw_long: @@ -902,6 +910,9 @@ bool Parser::isDeclarationSpecifier() const { case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: + + // GNU typeof support. + case tok::kw_typeof: // function-specifier case tok::kw_inline: @@ -1397,3 +1408,40 @@ void Parser::ParseBracketDeclarator(Declarator &D) { NumElements.Val, StartLoc)); } +/// [GNU] typeof-specifier: +/// typeof ( expressions ) +/// typeof ( type-name ) +/// +void Parser::ParseTypeofSpecifier(DeclSpec &DS) { + assert(Tok.getKind() == tok::kw_typeof && "Not a typeof specifier"); + SourceLocation StartLoc = ConsumeToken(); + + if (Tok.getKind() != tok::l_paren) { + // FIXME: handle error. + } + SourceLocation LParenLoc = ConsumeParen(), RParenLoc; + + if (isTypeSpecifierQualifier()) { + TypeTy *Ty = ParseTypeName(); + + const char *PrevSpec = 0; + bool isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, + PrevSpec, Ty); + // FIXME: what we have an invalid type? (or Ty is null) + } else { // we have an expression. + ExprResult Result = ParseExpression(); + if (Result.isInvalid) { + SkipUntil(tok::r_paren); + } + const char *PrevSpec = 0; + bool isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, + PrevSpec, Result.Val); + // FIXME: what we have an invalid type? (or Result.Val is null) + } + // Match the ')'. + if (Tok.getKind() == tok::r_paren) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); +} + diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 233c0bbcad..a14482b454 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1147,7 +1147,7 @@ inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 result = CheckSingleAssignmentConstraints(lhsType, rex); else result = CheckCompoundAssignmentConstraints(lhsType, rhsType); - + // decode the result (notice that extensions still return a type). switch (result) { case Compatible: diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp index cf72e38e2f..d70002340b 100644 --- a/Sema/SemaType.cpp +++ b/Sema/SemaType.cpp @@ -95,6 +95,18 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) { // TypeQuals handled by caller. return Ctx.getTypedefType(cast<TypedefDecl>(D)); } + case DeclSpec::TST_typeofType: { + QualType T = QualType::getFromOpaquePtr(DS.getTypeRep()); + assert(!T.isNull() && "Didn't get a type for typeof?"); + // TypeQuals handled by caller. + return Ctx.getTypeOfType(T); + } + case DeclSpec::TST_typeofExpr: { + Expr *E = static_cast<Expr *>(DS.getTypeRep()); + assert(E && "Didn't get an expression for typeof?"); + // TypeQuals handled by caller. + return Ctx.getTypeOfType(E); + } } } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index bb772fa182..ff84ac7c23 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -191,7 +191,7 @@ 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; }; - 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; + 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = "<group>"; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; }; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 93f5a64310..5d4c11b9cd 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -100,6 +100,10 @@ public: /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); + /// getTypeOfType - GCC extension. + QualType getTypeOfType(Expr *e); + QualType getTypeOfType(QualType t); + /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. QualType getTagDeclType(TagDecl *Decl); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index efd9cac22c..fa6490364d 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -189,7 +189,8 @@ public: enum TypeClass { Builtin, Complex, Pointer, Reference, Array, Vector, OCUVector, FunctionNoProto, FunctionProto, - TypeName, Tagged + TypeName, Tagged, + TypeOfExp, TypeOfTyp // GNU typeof extension. }; private: QualType CanonicalType; @@ -661,6 +662,37 @@ public: static bool classof(const TypedefType *) { return true; } }; +/// TypeOfExpr (GCC extension). +class TypeOfExpr : public Type { + Expr *TOExpr; + TypeOfExpr(Expr *E, QualType can) : Type(TypeOfExp, can), TOExpr(E) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return TOExpr; } + + virtual void getAsStringInternal(std::string &InnerString) const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExp; } + static bool classof(const TypeOfExpr *) { return true; } +}; + +/// TypeOfType (GCC extension). +class TypeOfType : public Type { + QualType TOType; + TypeOfType(QualType T, QualType can) : Type(TypeOfTyp, can), TOType(T) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getUnderlyingType() const { return TOType; } + + virtual void getAsStringInternal(std::string &InnerString) const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfTyp; } + static bool classof(const TypeOfType *) { return true; } +}; class TagType : public Type { TagDecl *Decl; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 7c5fb1a00b..aec81dac2f 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -75,7 +75,9 @@ public: TST_enum, TST_union, TST_struct, - TST_typedef + TST_typedef, + TST_typeofType, + TST_typeofExpr }; // type-qualifiers diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index bdae2e1458..522f6e0381 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -361,6 +361,7 @@ private: TypeTy *ParseTypeName(); AttributeList *ParseAttributes(); + void ParseTypeofSpecifier(DeclSpec &DS); /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); diff --git a/test/Parser/typeof.c b/test/Parser/typeof.c new file mode 100644 index 0000000000..4829713b27 --- /dev/null +++ b/test/Parser/typeof.c @@ -0,0 +1,18 @@ +// RUN: clang -parse-ast-check %s -pedantic + +typedef int TInt; + +static void test() { + int *pi; + + typeof(TInt) anInt; // expected-warning{{extension used}} + typeof(const int) aci; // expected-warning{{extension used}} + const typeof (*pi) aConstInt; // expected-warning{{extension used}} + int xx; + short typeof (*pi) aShortInt; // expected-error{{'short typeof' is invalid}} + int *i; + i = aci; // expected-warning{{incompatible types assigning 'typeof(int const)' to 'int *'}} + i = anInt; // expected-warning{{incompatible types assigning 'typeof(TInt)' to 'int *'}} + i = aConstInt; // expected-warning{{incompatible types assigning 'typeof(<expr>) const' to 'int *'}} + i = xx; // expected-warning{{incompatible types assigning 'int' to 'int *'}} +} |