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.

llvm-svn: 40631
This commit is contained in:
Steve Naroff 2007-07-31 12:34:36 +00:00
parent dd34d91e1a
commit ad373bdcfe
12 changed files with 147 additions and 4 deletions

View File

@ -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) {

View File

@ -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())

View File

@ -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";
}
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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);
}
}
}

View File

@ -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>"; };

View File

@ -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);

View File

@ -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;

View File

@ -75,7 +75,9 @@ public:
TST_enum,
TST_union,
TST_struct,
TST_typedef
TST_typedef,
TST_typeofType,
TST_typeofExpr
};
// type-qualifiers

View File

@ -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);

View File

@ -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 *'}}
}