r294778 - [c++1z] Enforce restriction that deduction guide is declared in the same scope as its template.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 10 12:39:59 PST 2017


Author: rsmith
Date: Fri Feb 10 14:39:58 2017
New Revision: 294778

URL: http://llvm.org/viewvc/llvm-project?rev=294778&view=rev
Log:
[c++1z] Enforce restriction that deduction guide is declared in the same scope as its template.

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

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294778&r1=294777&r2=294778&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 10 14:39:58 2017
@@ -1993,6 +1993,8 @@ def err_deduction_guide_name_not_class_t
   "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<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=294778&r1=294777&r2=294778&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Feb 10 14:39:58 2017
@@ -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,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=294778&r1=294777&r2=294778&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Feb 10 14:39:58 2017
@@ -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
     // 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?");

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=294778&r1=294777&r2=294778&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Feb 10 14:39:58 2017
@@ -242,6 +242,37 @@ TemplateNameKind Sema::isTemplateName(Sc
   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,

Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp?rev=294778&r1=294777&r2=294778&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Fri Feb 10 14:39:58 2017
@@ -40,28 +40,28 @@ template<typename T> A(T*) -> const A<T>
 // 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() {




More information about the cfe-commits mailing list