[cfe-commits] r142864 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Parse/Parser.h include/clang/Sema/Sema.h lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseStmt.cpp lib/Parse/Parser.cpp lib/Sema/SemaExprCXX.cpp test/SemaTemplate/ms-if-exists.cpp

Douglas Gregor dgregor at apple.com
Mon Oct 24 15:31:10 PDT 2011


Author: dgregor
Date: Mon Oct 24 17:31:10 2011
New Revision: 142864

URL: http://llvm.org/viewvc/llvm-project?rev=142864&view=rev
Log:
Rework Microsoft __if_exists/__if_not_exists parsing and semantic
analysis to separate dependent names from non-dependent names. For
dependent names, we'll behave differently from Visual C++:

  - For __if_exists/__if_not_exists at class scope, we'll just warn
    and then ignore them.
  - For __if_exists/__if_not_exists in statements, we'll treat the
    inner statement as a compound statement, which we only instantiate
    in templates where the dependent name (after instantiation)
    exists. This behavior is different from VC++, but it's as close as
    we can get without encroaching ridiculousness.

The latter part (dependent statements) is not yet implemented.


Added:
    cfe/trunk/test/SemaTemplate/ms-if-exists.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Oct 24 17:31:10 2011
@@ -75,6 +75,10 @@
   "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<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Oct 24 17:31:10 2011
@@ -488,6 +488,7 @@
                           const char *Msg = "", 
                           tok::TokenKind SkipToTok = tok::unknown);
     bool consumeClose();
+    void skipToEnd();
   };
 
   DelimiterTracker QuantityTracker;
@@ -1487,7 +1488,40 @@
   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,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct 24 17:31:10 2011
@@ -2591,7 +2591,20 @@
 
   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 ------------------------===//
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Oct 24 17:31:10 2011
@@ -2757,25 +2757,32 @@
 
 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 @@
     // 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();
 }

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Mon Oct 24 17:31:10 2011
@@ -2136,19 +2136,43 @@
 }
 
 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 @@
     if (R.isUsable())
       Stmts.push_back(R.release());
   }
-
-  if (Tok.isNot(tok::r_brace)) {
-    Diag(Tok, diag::err_expected_rbrace);
-    return;
-  }
-  ConsumeBrace();
+  Braces.consumeClose();
 }

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Oct 24 17:31:10 2011
@@ -1470,81 +1470,91 @@
   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);
-
-  Result = ((Condition.is(tok::kw___if_exists) && Exist) ||
-            (Condition.is(tok::kw___if_not_exists) && !Exist));
+  switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.SS, 
+                                               Result.Name)) {
+  case Sema::IER_Exists:
+    Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip;
+    break;
+
+  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 @@
   }
   return true;
 }
+
+void Parser::BalancedDelimiterTracker::skipToEnd() {
+  P.SkipUntil(Close, false);
+  Cleanup = false;
+}

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=142864&r1=142863&r2=142864&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Oct 24 17:31:10 2011
@@ -4665,17 +4665,37 @@
   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;
 }

Added: cfe/trunk/test/SemaTemplate/ms-if-exists.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-if-exists.cpp?rev=142864&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/ms-if-exists.cpp (added)
+++ cfe/trunk/test/SemaTemplate/ms-if-exists.cpp Mon Oct 24 17:31:10 2011
@@ -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);





More information about the cfe-commits mailing list