From: Francois Pichet Date: Wed, 8 Sep 2010 12:20:18 +0000 (+0000) Subject: Microsoft's __uuidof operator implementation part 1. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01b7c3028da5bbcb9f8e52ba67e4613070de0e60;p=clang Microsoft's __uuidof operator implementation part 1. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113356 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index cdabc75868..704a97cd61 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -396,6 +396,74 @@ public: virtual child_iterator child_end(); }; +/// CXXUuidofExpr - A microsoft C++ @c __uuidof expression, which gets +/// the _GUID that corresponds to the supplied type or expression. +/// +/// This represents code like @c __uuidof(COMTYPE) or @c __uuidof(*comPtr) +class CXXUuidofExpr : public Expr { +private: + llvm::PointerUnion Operand; + SourceRange Range; + +public: + CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, + false, Operand->getType()->isDependentType()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, + false, Operand->isTypeDependent()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXUuidofExprClass, Empty) { + if (isExpr) + Operand = (Expr*)0; + else + Operand = (TypeSourceInfo*)0; + } + + bool isTypeOperand() const { return Operand.is(); } + + /// \brief Retrieves the type operand of this __uuidof() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand() const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + return static_cast(Operand.get()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + Operand = E; + } + + virtual SourceRange getSourceRange() const { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUuidofExprClass; + } + static bool classof(const CXXUuidofExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// CXXThisExpr - Represents the "this" expression in C++, which is a /// pointer to the object on which the current member function is /// executing (C++ [expr.prim]p3). Example: diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 88ffd5ea2a..a41960d908 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1769,6 +1769,13 @@ DEF_TRAVERSE_STMT(CXXTypeidExpr, { TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); }) +DEF_TRAVERSE_STMT(CXXUuidofExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); + }) + DEF_TRAVERSE_STMT(TypesCompatibleExpr, { TRY_TO(TraverseTypeLoc(S->getArgTInfo1()->getTypeLoc())); TRY_TO(TraverseTypeLoc(S->getArgTInfo2()->getTypeLoc())); diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 438d0fc1f8..91b0b6aae2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2392,6 +2392,8 @@ def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; // Other C++ expressions def err_need_header_before_typeid : Error< "you need to include before using the 'typeid' operator">; +def err_need_header_before_ms_uuidof : Error< + "you need to include before using the '__uuidof' operator">; def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; def err_static_illegal_in_new : Error< "the 'static' modifier for the array size is not legal in new expressions">; diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 4aa055e695..7778a6d1db 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -127,3 +127,7 @@ def ObjCIsaExpr : DStmt; def ShuffleVectorExpr : DStmt; def BlockExpr : DStmt; def BlockDeclRefExpr : DStmt; + +// Microsoft Extensions. +def CXXUuidofExpr : DStmt; + diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index dc360adf8f..18f29c2249 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -369,11 +369,13 @@ ALIAS("__volatile__" , volatile , KEYALL) // Microsoft extensions which should be disabled in strict conformance mode KEYWORD(__ptr64 , KEYMS) KEYWORD(__w64 , KEYMS) +KEYWORD(__uuidof , KEYMS) ALIAS("_asm" , asm , KEYMS) ALIAS("_cdecl" , __cdecl , KEYMS) ALIAS("_fastcall" , __fastcall , KEYMS) ALIAS("_stdcall" , __stdcall , KEYMS) ALIAS("_thiscall" , __thiscall , KEYMS) +ALIAS("_uuidof" ,__uuidof , KEYMS) // Borland Extensions which should be disabled in strict conformance mode. ALIAS("_pascal" , __pascal , KEYBORLAND) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9c1630e899..a7dab1e667 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1028,6 +1028,10 @@ private: // C++ 5.2p1: C++ Type Identification ExprResult ParseCXXTypeid(); + //===--------------------------------------------------------------------===// + // C++ : Microsoft __uuidof Expression + ExprResult ParseCXXUuidof(); + //===--------------------------------------------------------------------===// // C++ 5.2.4: C++ Pseudo-Destructor Expressions ExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 09119861dc..845f4a5efe 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -365,6 +365,9 @@ public: /// standard library. LazyDeclPtr StdBadAlloc; + /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. + RecordDecl *MSVCGuidDecl; + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; @@ -2156,6 +2159,22 @@ public: void *TyOrExpr, SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXUuidof - Parse __uuidof( something ). + virtual ExprResult ActOnCXXUuidof(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation ThisLoc); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 0fa446dd34..f50b22801d 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -875,6 +875,8 @@ namespace clang { EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). EXPR_CXX_THIS, // CXXThisExpr EXPR_CXX_THROW, // CXXThrowExpr EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 8caf70b3e1..f72ab98eb8 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -39,6 +39,22 @@ Stmt::child_iterator CXXTypeidExpr::child_end() { : reinterpret_cast(&Operand) + 1; } +QualType CXXUuidofExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + +// CXXUuidofExpr - has child iterators if the operand is an expression +Stmt::child_iterator CXXUuidofExpr::child_begin() { + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand); +} +Stmt::child_iterator CXXUuidofExpr::child_end() { + return isTypeOperand() ? child_iterator() + : reinterpret_cast(&Operand) + 1; +} + // CXXBoolLiteralExpr Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { return child_iterator(); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 1778ce84d1..88e047ddc3 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1002,6 +1002,16 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << ")"; } +void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { + OS << "__uuidof("; + if (Node->isTypeOperand()) { + OS << Node->getTypeOperand().getAsString(Policy); + } else { + PrintExpr(Node->getExprOperand()); + } + OS << ")"; +} + void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { OS << (Node->getValue() ? "true" : "false"); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 78a336d2bf..843248cc0b 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -687,6 +687,12 @@ void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) { VisitType(S->getTypeOperand()); } +void StmtProfiler::VisitCXXUuidofExpr(CXXUuidofExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) { VisitExpr(S); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c4beab191d..6a7c72304c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -768,6 +768,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_typeid: Res = ParseCXXTypeid(); break; + case tok::kw___uuidof: + Res = ParseCXXUuidof(); + break; case tok::kw_this: Res = ParseCXXThis(); break; diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index c48ae7ccc1..18259ceb78 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -534,6 +534,54 @@ ExprResult Parser::ParseCXXTypeid() { return move(Result); } +/// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. +/// +/// '__uuidof' '(' expression ')' +/// '__uuidof' '(' type-id ')' +/// +ExprResult Parser::ParseCXXUuidof() { + assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); + + SourceLocation OpLoc = ConsumeToken(); + SourceLocation LParenLoc = Tok.getLocation(); + SourceLocation RParenLoc; + + // __uuidof expressions are always parenthesized. + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, + "__uuidof")) + return ExprError(); + + ExprResult Result; + + if (isTypeIdInParens()) { + TypeResult Ty = ParseTypeName(); + + // Match the ')'. + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + if (Ty.isInvalid()) + return ExprError(); + + Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/true, + Ty.get().getAsOpaquePtr(), RParenLoc); + } else { + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + Result = ParseExpression(); + + // Match the ')'. + if (Result.isInvalid()) + SkipUntil(tok::r_paren); + else { + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + Result = Actions.ActOnCXXUuidof(OpLoc, LParenLoc, /*isType=*/false, + Result.release(), RParenLoc); + } + } + + return move(Result); +} + /// \brief Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 17817d4169..60e8c14cf9 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -138,7 +138,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), SuppressAccessChecking(false), NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), - AnalysisWarnings(*this) + AnalysisWarnings(*this), MSVCGuidDecl(0) { TUScope = 0; if (getLangOptions().CPlusPlus) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7857ea9693..c3e2c50312 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -370,6 +370,62 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } +/// \brief Build a Microsoft __uuidof expression with a type operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + // FIXME: add __uuidof semantic analysis for type operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + Operand, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// \brief Build a Microsoft __uuidof expression with an expression operand. +ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *E, + SourceLocation RParenLoc) { + // FIXME: add __uuidof semantic analysis for expr operand. + return Owned(new (Context) CXXUuidofExpr(TypeInfoType.withConst(), + E, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); +ExprResult +Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, + bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // If MSVCGuidDecl has not been cached, do the lookup. + if (!MSVCGuidDecl) { + IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); + LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + MSVCGuidDecl = R.getAsSingle(); + if (!MSVCGuidDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); + } + + QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + + if (isType) { + // The operand is a type; handle it as such. + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), + &TInfo); + if (T.isNull()) + return ExprError(); + + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); + + return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); + } + + // The operand is an expression. + return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); +} + /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 16114f2ca3..746d6ca04c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1513,6 +1513,7 @@ public: RParenLoc); } + /// \brief Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1525,6 +1526,30 @@ public: RParenLoc); } + /// \brief Build a new C++ __uuidof(type) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, + RParenLoc); + } + + /// \brief Build a new C++ __uuidof(expr) expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, + RParenLoc); + } + /// \brief Build a new C++ "this" expression. /// /// By default, builds a new "this" expression without performing any @@ -5143,6 +5168,44 @@ TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E) { E->getLocEnd()); } +template +ExprResult +TreeTransform::TransformCXXUuidofExpr(CXXUuidofExpr *E) { + if (E->isTypeOperand()) { + TypeSourceInfo *TInfo + = getDerived().TransformType(E->getTypeOperandSourceInfo()); + if (!TInfo) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + TInfo == E->getTypeOperandSourceInfo()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), + TInfo, + E->getLocEnd()); + } + + // We don't know whether the expression is potentially evaluated until + // after we perform semantic analysis, so the expression is potentially + // potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + + ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + SubExpr.get() == E->getExprOperand()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildCXXUuidofExpr(E->getType(), + E->getLocStart(), + SubExpr.get(), + E->getLocEnd()); +} + template ExprResult TreeTransform::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 8bfca9431d..93664452d9 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -134,6 +134,7 @@ namespace clang { void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void VisitCXXUuidofExpr(CXXUuidofExpr *E); void VisitCXXThisExpr(CXXThisExpr *E); void VisitCXXThrowExpr(CXXThrowExpr *E); void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -1028,6 +1029,18 @@ void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { // typeid(42+2) E->setExprOperand(Reader.ReadSubExpr()); } +void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { + VisitExpr(E); + E->setSourceRange(Reader.ReadSourceRange(Record, Idx)); + if (E->isTypeOperand()) { // __uuidof(ComType) + E->setTypeOperandSourceInfo( + Reader.GetTypeSourceInfo(DeclsCursor, Record, Idx)); + return; + } + + // __uuidof(expr) + E->setExprOperand(Reader.ReadSubExpr()); +} void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { VisitExpr(E); @@ -1678,6 +1691,12 @@ Stmt *ASTReader::ReadStmtFromStream(llvm::BitstreamCursor &Cursor) { case EXPR_CXX_TYPEID_TYPE: S = new (Context) CXXTypeidExpr(Empty, false); break; + case EXPR_CXX_UUIDOF_EXPR: + S = new (Context) CXXUuidofExpr(Empty, true); + break; + case EXPR_CXX_UUIDOF_TYPE: + S = new (Context) CXXUuidofExpr(Empty, false); + break; case EXPR_CXX_THIS: S = new (Context) CXXThisExpr(Empty); break; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index cda42e1098..403311b8c1 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -131,6 +131,7 @@ namespace clang { void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void VisitCXXUuidofExpr(CXXUuidofExpr *E); void VisitCXXThisExpr(CXXThisExpr *E); void VisitCXXThrowExpr(CXXThrowExpr *E); void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -1039,6 +1040,18 @@ void ASTStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { } } +void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { + VisitExpr(E); + Writer.AddSourceRange(E->getSourceRange(), Record); + if (E->isTypeOperand()) { + Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record); + Code = serialization::EXPR_CXX_UUIDOF_TYPE; + } else { + Writer.AddStmt(E->getExprOperand()); + Code = serialization::EXPR_CXX_UUIDOF_EXPR; + } +} + void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) { VisitExpr(E); Writer.AddSourceLocation(E->getLocation(), Record); diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c index ec272cdf9c..105bb7f3a4 100644 --- a/test/Parser/MicrosoftExtensions.c +++ b/test/Parser/MicrosoftExtensions.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify -fms-extensions -Wno-missing-declarations -x objective-c++ %s +// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify -fms-extensions -Wno-unused-value -Wno-missing-declarations -x objective-c++ %s __stdcall int func0(); int __stdcall func(); typedef int (__cdecl *tptr)(); @@ -36,3 +36,40 @@ typedef bool (__stdcall __stdcall *blarg)(int); char x = FOO(a); typedef enum E { e1 }; + + +void uuidof_test1() +{ + __uuidof(0); // expected-error {{you need to include before using the '__uuidof' operator}} +} + +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; +struct __declspec(uuid("00000000-0000-0000-3231-000000000046")) A { }; +struct __declspec(uuid("00000000-0000-0000-1234-000000000047")) B { }; +class C {}; + +void uuidof_test2() +{ + A* a = new A; + B b; + __uuidof(A); + __uuidof(*a); + __uuidof(B); + __uuidof(&b); + _uuidof(0); + + // FIXME, this must not compile + _uuidof(1); + // FIXME, this must not compile + _uuidof(C); + + C c; + // FIXME, this must not compile + _uuidof(c); +}