2
0
Эх сурвалжийг харах

[templates] Fix issues with dependent template names (#3634)

Errors were reported for the use of some dependent template names
in cases where the code should have been accepted, caused by the
incorrect handling of some HLSL cases - which are fixed by this
change.

Fixes #3556
Tim Corringham 4 жил өмнө
parent
commit
3857ceedf1

+ 4 - 2
tools/clang/include/clang/Sema/Sema.h

@@ -5507,7 +5507,8 @@ public:
 
   void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
                           QualType ObjectType, bool EnteringContext,
-                          bool &MemberOfUnknownSpecialization);
+                          bool &MemberOfUnknownSpecialization,
+                          bool NextIsLess = false); // HLSL Change - additional special case flag
 
   TemplateNameKind isTemplateName(Scope *S,
                                   CXXScopeSpec &SS,
@@ -5516,7 +5517,8 @@ public:
                                   ParsedType ObjectType,
                                   bool EnteringContext,
                                   TemplateTy &Template,
-                                  bool &MemberOfUnknownSpecialization);
+                                  bool &MemberOfUnknownSpecialization,
+                                  bool NextIsLess = false); // HLSL Change - additional special case flag
 
   bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
                                    SourceLocation IILoc,

+ 5 - 5
tools/clang/lib/Parse/ParseExprCXX.cpp

@@ -553,7 +553,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
                                                         ObjectType,
                                                         EnteringContext,
                                                         Template,
-                                              MemberOfUnknownSpecialization)) {
+                                              MemberOfUnknownSpecialization,
+                                                        nextIsLess)) {  // HLSL Change
         // We have found a template name, so annotate this token
         // with a template-id annotation. We do not permit the
         // template-id to be translated into a type annotation,
@@ -569,10 +570,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
         continue;
       }
 
-      // HLSL Change: templates aren't really supported in HLSL unless the
-      // EnableTemplates option is enabled, so avoid handling other cases and
-      // emitting incorrect diagnostics if the template lookup fails.
-      if (!nextIsLess && getLangOpts().HLSL && !getLangOpts().EnableTemplates) {
+      // HLSL Change: avoid handling other cases and emitting incorrect
+      // diagnostics if the template lookup fails.
+      if (!nextIsLess && getLangOpts().HLSL) {
         break;
       }
 

+ 2 - 1
tools/clang/lib/Parse/Parser.cpp

@@ -1748,7 +1748,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
                                    /*hasTemplateKeyword=*/false, TemplateName,
                                    /*ObjectType=*/ ParsedType(),
                                    EnteringContext,
-                                   Template, MemberOfUnknownSpecialization)) {
+                                   Template, MemberOfUnknownSpecialization,
+                                   /*NextIsLess*/ true)) {  // HLSL Change - additional flag
         // Consume the identifier.
         ConsumeToken();
         if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(),

+ 1 - 1
tools/clang/lib/Sema/SemaDecl.cpp

@@ -602,7 +602,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
     return;
   }
 
-  if (getLangOpts().CPlusPlus) {
+  if (getLangOpts().CPlusPlus && !getLangOpts().HLSL) {  // HLSL Change
     // See if II is a class template that the user forgot to pass arguments to.
     UnqualifiedId Name;
     Name.setIdentifier(II, IILoc);

+ 16 - 9
tools/clang/lib/Sema/SemaTemplate.cpp

@@ -140,7 +140,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
                                       ParsedType ObjectTypePtr,
                                       bool EnteringContext,
                                       TemplateTy &TemplateResult,
-                                      bool &MemberOfUnknownSpecialization) {
+                                      bool &MemberOfUnknownSpecialization,
+                                      bool NextIsLess) { // HLSL CHange
   assert(getLangOpts().CPlusPlus && "No template names in C!");
 
   DeclarationName TName;
@@ -168,7 +169,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
 
   LookupResult R(*this, TName, Name.getLocStart(), LookupOrdinaryName);
   LookupTemplateName(R, S, SS, ObjectType, EnteringContext,
-                     MemberOfUnknownSpecialization);
+                     MemberOfUnknownSpecialization,
+                     NextIsLess); // HLSL Change
   if (R.empty()) return TNK_Non_template;
   if (R.isAmbiguous()) {
     // Suppress diagnostics;  we'll redo this lookup later.
@@ -248,7 +250,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
                               Scope *S, CXXScopeSpec &SS,
                               QualType ObjectType,
                               bool EnteringContext,
-                              bool &MemberOfUnknownSpecialization) {
+                              bool &MemberOfUnknownSpecialization,
+                              bool NextIsLess) { // HLSL Change
   // Determine where to perform name lookup
   MemberOfUnknownSpecialization = false;
   DeclContext *LookupCtx = nullptr;
@@ -319,9 +322,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
 
   // HLSL Change: do not try to save template name lookups with auto-correct,
   // otherwise identifiers like variable-names might match and fail;
-  // ideally we would still do this if 'nextIsLess' was known to be true,
-  // but this is a more localized change.
-  if (Found.empty() && !isDependent && !getLangOpts().HLSL) {
+  // however we still do this if 'NextIsLess' is known to be true.
+  if (Found.empty() && !isDependent && (!getLangOpts().HLSL || NextIsLess)) {
     // If we did not find any names, attempt to correct any typos.
     DeclarationName Name = Found.getLookupName();
     Found.clear();
@@ -3056,15 +3058,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
   case TemplateArgument::Template: {
     // We have a template type parameter but the template argument
     // is a template without any arguments.
+    // HLSL Change Starts
+    // We suppress some errors when templates are enabled in order to preserve
+    // backwards compatibility.
     SourceRange SR = AL.getSourceRange();
     TemplateName Name = Arg.getAsTemplate();
+    TemplateDecl *Decl = Name.getAsTemplateDecl();
+    if (Decl && !Decl->getLocation().isValid() && getLangOpts().EnableTemplates)
+      break;
     Diag(SR.getBegin(), diag::err_template_missing_args)
       << Name << SR;
-    if (TemplateDecl *Decl = Name.getAsTemplateDecl()) {
-      if (Decl->getLocation().isValid()) { // HLSL Change - ellide location notes for built-ins
+    if (Decl && Decl->getLocation().isValid()) { // HLSL Change - ellide location notes for built-ins
       Diag(Decl->getLocation(), diag::note_template_decl_here);
-      }
     }
+    // HLSL Change Ends
 
     return true;
   }

+ 27 - 0
tools/clang/test/HLSLFileCheck/hlsl/template/missing_typename.hlsl

@@ -0,0 +1,27 @@
+// RUN: %dxc -T vs_6_0 -E VSMain -enable-templates -DTYPENAME= %s | FileCheck %s -check-prefix=MISSING
+// RUN: %dxc -T vs_6_0 -E VSMain -enable-templates -DTYPENAME=typename %s | FileCheck %s -check-prefix=PRESENT
+
+// MISSING: error: missing 'typename' prior to dependent type name 'TVec::value_type'
+// PRESENT: define void @VSMain() {
+
+template <typename T>
+struct Vec2 {
+    T x, y;
+    T Length() {
+        return sqrt(x*x + y*y);
+    }
+    typedef T value_type;
+};
+
+template <typename TVec>
+TYPENAME TVec::value_type Length(TVec v) { // <-- Must be "typename TVec::value_type"
+    return v.Length();
+}
+
+void VSMain() {
+    Vec2<int> v_i;
+    Vec2<float> v_f;
+   
+    int   a = Length(v_i);
+    float b = Length(v_f);
+}