]> granicus.if.org Git - clang/commitdiff
[c++1z] Enforce restriction that deduction guide is declared in the same scope as...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2017 20:39:58 +0000 (20:39 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 10 Feb 2017 20:39:58 +0000 (20:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294778 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.deduct.guide/p3.cpp

index 4b199c6235844f74957f60bb3d0774b6be445c77..6bf33897d5d590eee8f22456e555c1d2f7938e76 100644 (file)
@@ -1993,6 +1993,8 @@ def err_deduction_guide_name_not_class_template : Error<
   "cannot specify deduction guide for "
   "%select{<error>|function template|variable template|alias template|"
   "template template parameter|dependent template name}0 %1">;
+def err_deduction_guide_wrong_scope : Error<
+  "deduction guide must be declared in the same scope as template %q0">;
 def err_deduction_guide_defines_function : Error<
   "deduction guide cannot have a function definition">;
 def err_deduction_guide_explicit_mismatch : Error<
index 01f52feb3ae3043b5e318ce925b4662ef4ca59cb..2fda45f55e4a13e5b9fa3ddceafddcc4d9887c66 100644 (file)
@@ -5831,17 +5831,7 @@ public:
   /// deduction-guide declaration.
   bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
                             SourceLocation NameLoc,
-                            ParsedTemplateTy *Template = nullptr) {
-    CXXScopeSpec SS;
-    UnqualifiedId Id;
-    Id.setIdentifier(&Name, NameLoc);
-    TemplateTy TemplateFallback;
-    bool MemberOfUnknownSpecialization;
-    // FIXME: Use redeclaration lookup!
-    return isTemplateName(S, SS, false, Id, ParsedType(), false,
-                          Template ? *Template : TemplateFallback,
-                          MemberOfUnknownSpecialization) == TNK_Type_template;
-  }
+                            ParsedTemplateTy *Template = nullptr);
 
   bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
                                    SourceLocation IILoc,
index c12c9b27bb923c3d41ec7abed25f5afc747874b5..2d5fd92cbb3121c9b92684da8b639eb4562dd569 100644 (file)
@@ -8137,6 +8137,20 @@ struct BadSpecifierDiagnoser {
 /// grammar.
 void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
                                          StorageClass &SC) {
+  TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
+  TemplateDecl *GuidedTemplateDecl = GuidedTemplate.getAsTemplateDecl();
+  assert(GuidedTemplateDecl && "missing template decl for deduction guide");
+
+  // C++ [temp.deduct.guide]p3:
+  //   A deduction-gide shall be declared in the same scope as the
+  //   corresponding class template.
+  if (!CurContext->getRedeclContext()->Equals(
+          GuidedTemplateDecl->getDeclContext()->getRedeclContext())) {
+    Diag(D.getIdentifierLoc(), diag::err_deduction_guide_wrong_scope)
+      << GuidedTemplateDecl;
+    Diag(GuidedTemplateDecl->getLocation(), diag::note_template_decl_here);
+  }
+
   auto &DS = D.getMutableDeclSpec();
   // We leave 'friend' and 'virtual' to be rejected in the normal way.
   if (DS.hasTypeSpecifier() || DS.getTypeQualifiers() ||
@@ -8196,7 +8210,6 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
     // Check that the return type is written as a specialization of
     // the template specified as the deduction-guide's name.
     ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
-    TemplateName GuidedTemplate = D.getName().TemplateName.get().get();
     TypeSourceInfo *TSI = nullptr;
     QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
     assert(TSI && "deduction guide has valid type but invalid return type?");
index 9d9d1270bf57b5a3d6078277526d9083c8930ef6..dd2dfe4235a9f8a5be316eb9bc93d160f641ae47 100644 (file)
@@ -242,6 +242,37 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
   return TemplateKind;
 }
 
+bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
+                                SourceLocation NameLoc,
+                                ParsedTemplateTy *Template) {
+  CXXScopeSpec SS;
+  bool MemberOfUnknownSpecialization = false;
+
+  // We could use redeclaration lookup here, but we don't need to: the
+  // syntactic form of a deduction guide is enough to identify it even
+  // if we can't look up the template name at all.
+  LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName);
+  LookupTemplateName(R, S, SS, /*ObjectType*/QualType(),
+                     /*EnteringContext*/false, MemberOfUnknownSpecialization);
+
+  if (R.empty()) return false;
+  if (R.isAmbiguous()) {
+    // FIXME: Diagnose an ambiguity if we find at least one template.
+    R.suppressDiagnostics();
+    return false;
+  }
+
+  // We only treat template-names that name type templates as valid deduction
+  // guide names.
+  TemplateDecl *TD = R.getAsSingle<TemplateDecl>();
+  if (!TD || !getAsTypeTemplateDecl(TD))
+    return false;
+
+  if (Template)
+    *Template = TemplateTy::make(TemplateName(TD));
+  return true;
+}
+
 bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
                                        SourceLocation IILoc,
                                        Scope *S,
index 88654ac69ab1ee405bee0f9460a20816b8f60a73..e12f7b6ef255e18e5fa93eaaacfb66ba7b73a398 100644 (file)
@@ -40,28 +40,28 @@ template<typename T> A(T*) -> const A<T>; // expected-error {{deduced type 'cons
 // class template.
 namespace WrongScope {
   namespace {
-    template<typename T> struct AnonNS1 {};
+    template<typename T> struct AnonNS1 {}; // expected-note {{here}}
     AnonNS1(float) -> AnonNS1<float>; // ok
   }
-  AnonNS1(int) -> AnonNS1<int>; // FIXME
-  template<typename T> struct AnonNS2 {};
+  AnonNS1(int) -> AnonNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::}}
+  template<typename T> struct AnonNS2 {}; // expected-note {{here}}
   namespace {
     AnonNS1(char) -> AnonNS1<char>; // ok
-    AnonNS2(int) -> AnonNS2<int>; // FIXME
+    AnonNS2(int) -> AnonNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::AnonNS2'}}
   }
   namespace N {
-    template<typename T> struct NamedNS1 {};
-    template<typename T> struct NamedNS2 {};
+    template<typename T> struct NamedNS1 {}; // expected-note {{here}}
+    template<typename T> struct NamedNS2 {}; // expected-note {{here}}
   }
   using N::NamedNS1;
-  NamedNS1(int) -> NamedNS1<int>; // FIXME
+  NamedNS1(int) -> NamedNS1<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
   using namespace N;
-  NamedNS2(int) -> NamedNS2<int>; // FIXME
+  NamedNS2(int) -> NamedNS2<int>; // expected-error {{deduction guide must be declared in the same scope as template}}
   struct ClassMemberA {
-    template<typename T> struct X {};
+    template<typename T> struct X {}; // expected-note {{here}}
   };
   struct ClassMemberB : ClassMemberA {
-    X(int) -> X<int>; // FIXME
+    X(int) -> X<int>; // expected-error {{deduction guide must be declared in the same scope as template 'WrongScope::ClassMemberA::X'}}
   };
   template<typename T> struct Local {};
   void f() {