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
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp
index a9fb81f..6f71651 100644
--- a/AST/ASTContext.cpp
+++ b/AST/ASTContext.cpp
@@ -584,6 +584,18 @@
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 214dbea..ecade56 100644
--- a/AST/Type.cpp
+++ b/AST/Type.cpp
@@ -638,6 +638,18 @@
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 d3ddf47..31338d8 100644
--- a/Parse/DeclSpec.cpp
+++ b/Parse/DeclSpec.cpp
@@ -98,6 +98,8 @@
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 b05fd78..6b5215b 100644
--- a/Parse/ParseDecl.cpp
+++ b/Parse/ParseDecl.cpp
@@ -482,6 +482,11 @@
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 @@
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 @@
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 @@
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 233c0bb..a14482b 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -1147,7 +1147,7 @@
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 cf72e38..d700023 100644
--- a/Sema/SemaType.cpp
+++ b/Sema/SemaType.cpp
@@ -95,6 +95,18 @@
// 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 bb772fa..ff84ac7 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 93f5a64..5d4c11b 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -100,6 +100,10 @@
/// 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 efd9cac..fa64903 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -189,7 +189,8 @@
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 @@
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 7c5fb1a..aec81da 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -75,7 +75,9 @@
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 bdae2e1..522f6e0 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -361,6 +361,7 @@
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 0000000..4829713
--- /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 *'}}
+}