rnk created this revision.
rnk added reviewers: avt77, rsmith.
rnk added a subscriber: cfe-commits.

In dependent contexts where we know a type name is required, such as a
new expression, we can recover by forming a DependentNameType.

Works towards parsing atlctrlw.h, which is PR26748.

http://reviews.llvm.org/D20500

Files:
  include/clang/Sema/Sema.h
  lib/Parse/ParseDecl.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaTemplate/ms-delayed-default-template-args.cpp
  test/SemaTemplate/ms-lookup-template-base-classes.cpp

Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp
===================================================================
--- test/SemaTemplate/ms-lookup-template-base-classes.cpp
+++ test/SemaTemplate/ms-lookup-template-base-classes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s
 
 
 template <class T>
@@ -573,3 +573,28 @@
 template <typename T> decltype(h(T())) check2(); // expected-note{{candidate template ignored: substitution failure [with T = int]: no matching function for call to 'h'}}
 decltype(check2<int>()) y; // expected-error{{no matching function for call to 'check2'}}
 }
+
+// We also allow unqualified lookup into bases in contexts where the we know the
+// undeclared identifier *must* be a type, such as a new expression or catch
+// parameter type.
+template <typename T>
+struct UseUnqualifiedTypeNames : T {
+  _Atomic (TheType) f2; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+  void foo() {
+    void *P = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    size_t x = __builtin_offsetof(TheType, f2); // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    try {
+    } catch (TheType) { // expected-warning {{unqualified lookup}} expected-error {{no type}}
+    }
+    enum E : IntegerType { E0 = 42 }; // expected-warning {{unqualified lookup}} expected-error {{no type}}
+  }
+};
+struct Base {
+  typedef int IntegerType;
+  struct TheType {
+    int f1, f2;
+  };
+};
+template struct UseUnqualifiedTypeNames<Base>;
+struct BadBase { };
+template struct UseUnqualifiedTypeNames<BadBase>; // expected-note-re 2 {{in instantiation {{.*}} requested here}}
Index: test/SemaTemplate/ms-delayed-default-template-args.cpp
===================================================================
--- test/SemaTemplate/ms-delayed-default-template-args.cpp
+++ test/SemaTemplate/ms-delayed-default-template-args.cpp
@@ -55,6 +55,15 @@
 typedef int Weber;
 }
 
+// MSVC accepts this, but Clang doesn't.
+namespace test_scope_spec {
+template <typename T = ns::Bar>  // expected-error {{use of undeclared identifier 'ns'}}
+struct Foo {
+  static_assert(sizeof(T) == 4, "Bar should have gotten int");
+};
+namespace ns { typedef int Bar; }
+}
+
 #ifdef __clang__
 // These are negative test cases that MSVC doesn't compile either.  Try to use
 // unique undeclared identifiers so typo correction doesn't find types declared
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -475,6 +475,8 @@
 
 ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
                                                 SourceLocation NameLoc) {
+  assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode");
+
   // Accepting an undeclared identifier as a default argument for a template
   // type parameter is a Microsoft extension.
   Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
@@ -500,6 +502,50 @@
   return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
 }
 
+static const CXXRecordDecl *
+findRecordParentWithDependentBases(const DeclContext *DC) {
+  for (;; DC = DC->getLookupParent()) {
+    DC = DC->getPrimaryContext();
+    if (auto *RD = dyn_cast<CXXRecordDecl>(DC))
+      if (RD->hasAnyDependentBases())
+        return RD;
+  }
+  return nullptr;
+}
+
+ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
+                                          SourceLocation NameLoc) {
+  assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode");
+
+  const CXXRecordDecl *RD = findRecordParentWithDependentBases(CurContext);
+  if (!RD)
+    return ParsedType();
+
+  // Diagnose that this identifier was undeclared, and retry the lookup during
+  // template instantiation.
+  Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II
+                                                                    << RD;
+
+  // Build a DependentNameType that will perform lookup into RD at instantiation
+  // time.
+  NestedNameSpecifier *NNS = NestedNameSpecifier::Create(
+      Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl());
+  QualType T = Context.getDependentNameType(ETK_None, NNS, &II);
+
+  // Build type location information.  We synthesized the qualifier, so we have
+  // to build a fake NestedNameSpecifierLoc.
+  NestedNameSpecifierLocBuilder NNSLocBuilder;
+  NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc));
+  NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context);
+
+  TypeLocBuilder Builder;
+  DependentNameTypeLoc DepTL = Builder.push<DependentNameTypeLoc>(T);
+  DepTL.setNameLoc(NameLoc);
+  DepTL.setElaboratedKeywordLoc(SourceLocation());
+  DepTL.setQualifierLoc(QualifierLoc);
+  return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+}
+
 /// isTagName() - This method is called *for error recovery purposes only*
 /// to determine if the specified name is a valid tag name ("struct foo").  If
 /// so, this returns the TST for the tag corresponding to it (TST_enum,
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -2986,14 +2986,21 @@
         Actions.getTypeName(*Tok.getIdentifierInfo(),
                             Tok.getLocation(), getCurScope());
 
-      // MSVC: If we weren't able to parse a default template argument, and it's
-      // just a simple identifier, create a DependentNameType.  This will allow
-      // us to defer the name lookup to template instantiation time, as long we
-      // forge a NestedNameSpecifier for the current context.
-      if (!TypeRep && DSContext == DSC_template_type_arg &&
-          getLangOpts().MSVCCompat && getCurScope()->isTemplateParamScope()) {
-        TypeRep = Actions.ActOnDelayedDefaultTemplateArg(
-            *Tok.getIdentifierInfo(), Tok.getLocation());
+      if (!TypeRep && getLangOpts().MSVCCompat) {
+        if (DSContext == DSC_type_specifier) {
+          // Lookup failed in a context where we know we need a type. Try to
+          // recover if this was type from a dependent base class.
+          TypeRep = Actions.ActOnMSVCUnknownTypeName(*Tok.getIdentifierInfo(),
+                                                     Tok.getLocation());
+        } else if (DSContext == DSC_template_type_arg &&
+                   getCurScope()->isTemplateParamScope()) {
+          // If we weren't able to parse a default template argument, and it's
+          // just a simple identifier, create a DependentNameType.  This will
+          // allow us to defer the name lookup to template instantiation time,
+          // as long we forge a NestedNameSpecifier for the current context.
+          TypeRep = Actions.ActOnDelayedDefaultTemplateArg(
+              *Tok.getIdentifierInfo(), Tok.getLocation());
+        }
       }
 
       // If this is not a typedef name, don't parse it as part of the declspec,
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1535,6 +1535,8 @@
   /// other template arguments.
   ParsedType ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
                                             SourceLocation NameLoc);
+  ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
+                                      SourceLocation NameLoc);
 
   /// \brief Describes the result of the name lookup and resolution performed
   /// by \c ClassifyName().
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to