diff options
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 36 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 15 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 33 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 43 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 81 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 30 | ||||
-rw-r--r-- | test/SemaTemplate/ms-if-exists.cpp | 53 |
8 files changed, 228 insertions, 67 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index f0add4c067..8595c43aa8 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -75,6 +75,10 @@ def warn_cxx98_compat_alignof : Warning< "alignof expressions are incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_microsoft_dependent_exists : Warning< + "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, + InGroup<DiagGroup<"microsoft-exists">>; + def ext_c1x_generic_selection : Extension< "generic selections are a C1X-specific feature">, InGroup<C1X>; def err_duplicate_default_assoc : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3bf473cbe1..d8a13e7bc4 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -488,6 +488,7 @@ private: const char *Msg = "", tok::TokenKind SkipToTok = tok::unknown); bool consumeClose(); + void skipToEnd(); }; DelimiterTracker QuantityTracker; @@ -1487,7 +1488,40 @@ private: StmtResult ParseReturnStatement(ParsedAttributes &Attr); StmtResult ParseAsmStatement(bool &msAsm); StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); - bool ParseMicrosoftIfExistsCondition(bool& Result); + + /// \brief Describes the behavior that should be taken for an __if_exists + /// block. + enum IfExistsBehavior { + /// \brief Parse the block; this code is always used. + IEB_Parse, + /// \brief Skip the block entirely; this code is never used. + IEB_Skip, + /// \brief Parse the block as a dependent block, which may be used in + /// some template instantiations but not others. + IEB_Dependent + }; + + /// \brief Describes the condition of a Microsoft __if_exists or + /// __if_not_exists block. + struct IfExistsCondition { + /// \brief The location of the initial keyword. + SourceLocation KeywordLoc; + /// \brief Whether this is an __if_exists block (rather than an + /// __if_not_exists block). + bool IsIfExists; + + /// \brief Nested-name-specifier preceding the name. + CXXScopeSpec SS; + + /// \brief The name we're looking for. + UnqualifiedId Name; + + /// \brief The behavior of this __if_exists or __if_not_exists block + /// should. + IfExistsBehavior Behavior; +}; + + bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result); void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); void ParseMicrosoftIfExistsExternalDeclaration(); void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 024d273437..22a308dd2a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2591,7 +2591,20 @@ public: bool CheckCaseExpression(Expr *E); - bool CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, UnqualifiedId &Name); + /// \brief Describes the result of an "if-exists" condition check. + enum IfExistsResult { + /// \brief The symbol exists. + IER_Exists, + + /// \brief The symbol does not exist. + IER_DoesNotExist, + + /// \brief The name is a dependent name, so it + IER_Dependent + }; + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name); //===------------------------- "Block" Extension ------------------------===// diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7583ccafeb..3d3d7c21cb 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2757,25 +2757,32 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, AccessSpecifier& CurAS) { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse the declarations below. + break; + + case IEB_Dependent: + Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists) + << Result.IsIfExists; + // Fall through to skip. + + case IEB_Skip: + Braces.skipToEnd(); return; } - // Condition is true, parse the declaration. - while (Tok.isNot(tok::r_brace)) { - + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // __if_exists, __if_not_exists can nest. if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) { ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS); @@ -2808,10 +2815,6 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS, 0); } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + + Braces.consumeClose(); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 8968a43480..5c2ed4e5f5 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2136,19 +2136,43 @@ StmtResult Parser::ParseCXXCatchBlock() { } void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + // Handle dependent statements by parsing the braces as a compound statement. + // This is not the same behavior as Visual C++, which don't treat this as a + // compound statement, but for Clang's type checking we can't have anything + // inside these braces escaping to the surrounding code. + if (Result.Behavior == IEB_Dependent) { + if (!Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + + ParsedAttributes Attrs(AttrFactory); + StmtResult Compound = ParseCompoundStatement(Attrs); + // FIXME: We're dropping these statements on the floor. + return; + } + + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse the statements below. + break; + + case IEB_Dependent: + llvm_unreachable("Dependent case handled above"); + break; + + case IEB_Skip: + Braces.skipToEnd(); return; } @@ -2158,10 +2182,5 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { if (R.isUsable()) Stmts.push_back(R.release()); } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + Braces.consumeClose(); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 2face304c0..90bed04e75 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1470,81 +1470,91 @@ void Parser::CodeCompleteNaturalLanguage() { Actions.CodeCompleteNaturalLanguage(); } -bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) { +bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) && "Expected '__if_exists' or '__if_not_exists'"); - Token Condition = Tok; - SourceLocation IfExistsLoc = ConsumeToken(); + Result.IsIfExists = Tok.is(tok::kw___if_exists); + Result.KeywordLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { - Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; - SkipUntil(tok::semi); + Diag(Tok, diag::err_expected_lparen_after) + << (Result.IsIfExists? "__if_exists" : "__if_not_exists"); return true; } // Parse nested-name-specifier. - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParseOptionalCXXScopeSpecifier(Result.SS, ParsedType(), false); // Check nested-name specifier. - if (SS.isInvalid()) { - SkipUntil(tok::semi); + if (Result.SS.isInvalid()) { + T.skipToEnd(); return true; } // Parse the unqualified-id. - UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { - SkipUntil(tok::semi); + if (ParseUnqualifiedId(Result.SS, false, true, true, ParsedType(), + Result.Name)) { + T.skipToEnd(); return true; } - T.consumeClose(); - if (T.getCloseLocation().isInvalid()) + if (T.consumeClose()) return true; - + // Check if the symbol exists. - bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name); + switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.SS, + Result.Name)) { + case Sema::IER_Exists: + Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; - Result = ((Condition.is(tok::kw___if_exists) && Exist) || - (Condition.is(tok::kw___if_not_exists) && !Exist)); + case Sema::IER_DoesNotExist: + Result.Behavior = !Result.IsIfExists ? IEB_Parse : IEB_Skip; + break; + + case Sema::IER_Dependent: + Result.Behavior = IEB_Dependent; + break; + } return false; } void Parser::ParseMicrosoftIfExistsExternalDeclaration() { - bool Result; + IfExistsCondition Result; if (ParseMicrosoftIfExistsCondition(Result)) return; - if (Tok.isNot(tok::l_brace)) { + BalancedDelimiterTracker Braces(*this, tok::l_brace); + if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); return; } - ConsumeBrace(); - // Condition is false skip all inside the {}. - if (!Result) { - SkipUntil(tok::r_brace, false); + switch (Result.Behavior) { + case IEB_Parse: + // Parse declarations below. + break; + + case IEB_Dependent: + llvm_unreachable("Cannot have a dependent external declaration"); + + case IEB_Skip: + Braces.skipToEnd(); return; } - // Condition is true, parse the declaration. - while (Tok.isNot(tok::r_brace)) { + // Parse the declarations. + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); DeclGroupPtrTy Result = ParseExternalDeclaration(attrs); if (Result && !getCurScope()->getParent()) Actions.getASTConsumer().HandleTopLevelDecl(Result.get()); - } - - if (Tok.isNot(tok::r_brace)) { - Diag(Tok, diag::err_expected_rbrace); - return; - } - ConsumeBrace(); + } + Braces.consumeClose(); } Parser::DeclGroupPtrTy Parser::ParseModuleImport() { @@ -1629,3 +1639,8 @@ bool Parser::BalancedDelimiterTracker::consumeClose() { } return true; } + +void Parser::BalancedDelimiterTracker::skipToEnd() { + P.SkipUntil(Close, false); + Cleanup = false; +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 64a9dd9c76..c4571c96d0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4665,17 +4665,37 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } -bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, - UnqualifiedId &Name) { +Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, + CXXScopeSpec &SS, + UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) - return false; + return IER_DoesNotExist; + // If the name itself is dependent, then the result is dependent. + if (TargetName.isDependentName()) + return IER_Dependent; + // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); + LookupParsedName(R, S, &SS); R.suppressDiagnostics(); - LookupParsedName(R, getCurScope(), &SS); - return !R.empty(); + + switch (R.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + case LookupResult::Ambiguous: + return IER_Exists; + + case LookupResult::NotFound: + return IER_DoesNotExist; + + case LookupResult::NotFoundInCurrentInstantiation: + return IER_Dependent; + } + + return IER_DoesNotExist; } diff --git a/test/SemaTemplate/ms-if-exists.cpp b/test/SemaTemplate/ms-if-exists.cpp new file mode 100644 index 0000000000..f22a8997b1 --- /dev/null +++ b/test/SemaTemplate/ms-if-exists.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -fms-extensions %s -verify + +struct Nontemplate { + typedef int type; +}; + +template<typename T> +struct X { + __if_exists(Nontemplate::type) { + typedef Nontemplate::type type; + } + + __if_exists(Nontemplate::value) { + typedef Nontemplate::value type2; + } + + __if_not_exists(Nontemplate::value) { + typedef int type3; + } + + __if_exists(T::X) { // expected-warning{{dependent __if_exists declarations are ignored}} + typedef T::X type4; + } +}; + +X<int>::type i1; +X<int>::type2 i2; // expected-error{{no type named 'type2' in 'X<int>'}} +X<int>::type3 i3; +X<int>::type4 i4; // expected-error{{no type named 'type4' in 'X<int>'}} + +struct HasFoo { + void foo(); +}; +struct HasBar { + void bar(int); + void bar(float); +}; + +template<typename T> +void f(T t) { + __if_exists(T::foo) { + { } + t.foo(); + } + + __if_not_exists(T::bar) { + int *i = t; + { } + } +} + +template void f(HasFoo); +template void f(HasBar); |