From 6fd634f4ac59f5923cffadadb99d19f23c18707a Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Wed, 24 Jun 2009 17:47:40 +0000 Subject: [PATCH] Parse the C++0x decltype specifier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74086 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/DeclSpec.h | 1 + include/clang/Parse/Parser.h | 1 + lib/Parse/ParseDecl.cpp | 10 ++++++++ lib/Parse/ParseDeclCXX.cpp | 47 ++++++++++++++++++++++++++++++++++ lib/Parse/ParseTentative.cpp | 7 ++++- lib/Sema/SemaType.cpp | 11 ++++++++ 6 files changed, 76 insertions(+), 1 deletion(-) diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index a0b9b1e7cc..10c5ee39ec 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -82,6 +82,7 @@ public: TST_typename, // Typedef, C++ class-name or enum name, etc. TST_typeofType, TST_typeofExpr, + TST_decltype, // C++0x decltype TST_error // erroneous type }; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 8908201234..7a1c90a259 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1071,6 +1071,7 @@ private: AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0); AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0); void ParseTypeofSpecifier(DeclSpec &DS); + void ParseDecltypeSpecifier(DeclSpec &DS); /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 7153bad5ab..9a8e34211d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1025,6 +1025,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseTypeofSpecifier(DS); continue; + case tok::kw_decltype: + ParseDecltypeSpecifier(DS); + continue; + case tok::less: // GCC ObjC supports types like "" as a synonym for // "id". This is hopelessly old fashioned and dangerous, @@ -1102,6 +1106,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /// [GNU] typeof-specifier /// [OBJC] class-name objc-protocol-refs[opt] [TODO] /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] +/// [C++0x] 'decltype' ( expression ) bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, const char *&PrevSpec, const ParsedTemplateInfo &TemplateInfo) { @@ -1242,6 +1247,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, ParseTypeofSpecifier(DS); return true; + // C++0x decltype support. + case tok::kw_decltype: + ParseDecltypeSpecifier(DS); + return true; + case tok::kw___ptr64: case tok::kw___w64: case tok::kw___cdecl: diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 44f231a667..188580de20 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -355,6 +355,53 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ move(AssertMessage)); } +/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// +/// 'decltype' ( expression ) +/// +void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { + assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier"); + + SourceLocation StartLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + + + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "decltype")) { + SkipUntil(tok::r_paren); + return; + } + + + // Parse the expression + + // C++0x [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, + Action::Unevaluated); + OwningExprResult Result = ParseExpression(); + if (Result.isInvalid()) { + SkipUntil(tok::r_paren); + return; + } + + // Match the ')' + SourceLocation RParenLoc; + if (Tok.is(tok::r_paren)) + RParenLoc = ConsumeParen(); + else + MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (RParenLoc.isInvalid()) + return; + + const char *PrevSpec = 0; + // Check for duplicate type specifiers (e.g. "int decltype(a)"). + if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + Result.release())) + Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec; +} + /// ParseClassName - Parse a C++ class-name, which names a class. Note /// that we only check that the result names a type; semantic analysis /// will need to verify that the type names a class. The result is diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index f31855b751..02687a216c 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -543,6 +543,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, /// [GNU] typeof-specifier /// [GNU] '_Complex' /// [C++0x] 'auto' [TODO] +/// [C++0x] 'decltype' ( expression ) /// /// type-name: /// class-name @@ -695,7 +696,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return TPResult::True(); - // GNU typeof support. + // GNU typeof support. case tok::kw_typeof: { if (NextToken().isNot(tok::l_paren)) return TPResult::True(); @@ -716,6 +717,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return TPResult::True(); } + // C++0x decltype support. + case tok::kw_decltype: + return TPResult::True(); + default: return TPResult::False(); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 967f650d13..297dee9a50 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -236,6 +236,17 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getTypeOfExprType(E); break; } + case DeclSpec::TST_decltype: { + Expr *E = static_cast(DS.getTypeRep()); + assert(E && "Didn't get an expression for decltype?"); + // TypeQuals handled by caller. + + // FIXME: Use the right type! + Result = Context.IntTy; + isInvalid = true; + break; + } + case DeclSpec::TST_error: Result = Context.IntTy; isInvalid = true;