aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Naroff <snaroff@apple.com>2007-07-31 12:34:36 +0000
committerSteve Naroff <snaroff@apple.com>2007-07-31 12:34:36 +0000
commitd1861fd633d5096a00777c918eb8575ea7162fe7 (patch)
treecd71c78f1c513b18ab427f6036aa2debdcb7d93a
parent8a2bc625e86983e250ed31040695a870a767196b (diff)
Add parsing and AST support for GNU "typeof".
Many small changes to lot's of files. Still some FIXME's, however the basic support is in place. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40631 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--AST/ASTContext.cpp12
-rw-r--r--AST/Type.cpp12
-rw-r--r--Parse/DeclSpec.cpp2
-rw-r--r--Parse/ParseDecl.cpp48
-rw-r--r--Sema/SemaExpr.cpp2
-rw-r--r--Sema/SemaType.cpp12
-rw-r--r--clang.xcodeproj/project.pbxproj2
-rw-r--r--include/clang/AST/ASTContext.h4
-rw-r--r--include/clang/AST/Type.h34
-rw-r--r--include/clang/Parse/DeclSpec.h4
-rw-r--r--include/clang/Parse/Parser.h1
-rw-r--r--test/Parser/typeof.c18
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 *'}}
+}