Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang-cl] Self instantiation does not work in a constant expression #108962

Open
VladimirShchigolev opened this issue Sep 17, 2024 · 3 comments
Open
Labels
c++ clang:frontend Language frontend issues, e.g. anything involving "Sema" constexpr Anything related to constant evaluation

Comments

@VladimirShchigolev
Copy link

Consider the following example:

template <int I = 0>
struct S {
	static constexpr int A = I;
	static constexpr int B = S<>::A;
};
static_assert(S<1>::B == 0, "S<1>::B should be 0");

Latest MSVC (14.41) is able to compile this:

C:\test>cl.exe /c example.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34120 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

example.cpp

However clang-cl fails to compile:

C:\test>clang-cl.exe example.cpp
C:\test\example.cpp(4,30): error: implicit instantiation of
	  template 'S<>' within its own definition
	4 |     static constexpr int B = S<>::A;
	  |                              ^
C:\test\example.cpp(4,26): error: constexpr variable 'B' must
	  be initialized by a constant expression
	4 |     static constexpr int B = S<>::A;
	  |                          ^
	  |                            = 0
2 errors generated.

Here is a draft patch that I tried to make while working at #47033. It does not work - it removes the errors, but the assert fails. Maybe it will help.

Parent: 520ddf22b2270dc092dbdbd391b1c02c403b475a ([TableGen] Remove duplicate code in applyMnemonicAliases when target uses DefaultAsmParserVariant. (#108494))

------------------------- clang/lib/Sema/SemaDecl.cpp -------------------------
index 3c6a0dff798f..6a12ed82894d 100644
@@ -352,7 +352,26 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
       return nullptr;
     }
 
-    if (!LookupCtx->isDependentContext() &&
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S->getLookupEntity())
+      DeclFromScope = dyn_cast_or_null<CXXRecordDecl>(S->getLookupEntity());
+
+    if (SS->isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ 		      SS->getScopeRep()->getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl && 
+    		  ClassTemplateSpecDecl->getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl->
+ 		    getSpecializedTemplate()->getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat && DeclFromScope && 
+  		  DeclFromScope == DeclFromScopeSpec) {
+      LookupCtx = nullptr;
+  		SS = nullptr;
+    } else if (!LookupCtx->isDependentContext() &&
         RequireCompleteDeclContext(*SS, LookupCtx))
       return nullptr;
   }

------------------------ clang/lib/Sema/SemaLookup.cpp ------------------------
index d3d4bf27ae72..de7b7fbba9b3 100644
@@ -2695,6 +2695,25 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
             ObjectType->castAs<TagType>()->isBeingDefined()) &&
            "Caller should have completed object type");
   } else if (SS && SS->isNotEmpty()) {
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S->getLookupEntity())
+      DeclFromScope = dyn_cast_or_null<CXXRecordDecl>(S->getLookupEntity());
+
+    if (SS->isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ 		      SS->getScopeRep()->getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl && 
+    		  ClassTemplateSpecDecl->getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl->
+ 		    getSpecializedTemplate()->getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat && DeclFromScope && 
+  		  DeclFromScope == DeclFromScopeSpec)
+      return LookupName(R, S, AllowBuiltinCreation);
+        
     // This nested-name-specifier occurs after another nested-name-specifier,
     // so long into the context associated with the prior nested-name-specifier.
     if ((DC = computeDeclContext(*SS, EnteringContext))) {
@RIscRIpt RIscRIpt added c++ clang:frontend Language frontend issues, e.g. anything involving "Sema" clang-cl `clang-cl` driver. Don't use for other compiler parts labels Sep 17, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2024

@llvm/issue-subscribers-c-1

Author: None (VladimirShchigolev)

Consider the following example: ``` template <int I = 0> struct S { static constexpr int A = I; static constexpr int B = S<>::A; }; static_assert(S<1>::B == 0, "S<1>::B should be 0"); ```

Latest MSVC (14.41) is able to compile this:

C:\test&gt;cl.exe /c example.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34120 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

example.cpp

However clang-cl fails to compile:

C:\test&gt;clang-cl.exe example.cpp
C:\test\example.cpp(4,30): error: implicit instantiation of
	  template 'S&lt;&gt;' within its own definition
	4 |     static constexpr int B = S&lt;&gt;::A;
	  |                              ^
C:\test\example.cpp(4,26): error: constexpr variable 'B' must
	  be initialized by a constant expression
	4 |     static constexpr int B = S&lt;&gt;::A;
	  |                          ^
	  |                            = 0
2 errors generated.

Here is a draft patch that I tried to make while working at #47033. It does not work - it removes the errors, but the assert fails. Maybe it will help.

Parent: 520ddf22b2270dc092dbdbd391b1c02c403b475a ([TableGen] Remove duplicate code in applyMnemonicAliases when target uses DefaultAsmParserVariant. (#<!-- -->108494))

------------------------- clang/lib/Sema/SemaDecl.cpp -------------------------
index 3c6a0dff798f..6a12ed82894d 100644
@@ -352,7 +352,26 @@ ParsedType Sema::getTypeName(const IdentifierInfo &amp;II, SourceLocation NameLoc,
       return nullptr;
     }
 
-    if (!LookupCtx-&gt;isDependentContext() &amp;&amp;
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S-&gt;getLookupEntity())
+      DeclFromScope = dyn_cast_or_null&lt;CXXRecordDecl&gt;(S-&gt;getLookupEntity());
+
+    if (SS-&gt;isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null&lt;ClassTemplateSpecializationDecl&gt;(
+ 		      SS-&gt;getScopeRep()-&gt;getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl &amp;&amp; 
+    		  ClassTemplateSpecDecl-&gt;getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl-&gt;
+ 		    getSpecializedTemplate()-&gt;getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat &amp;&amp; DeclFromScope &amp;&amp; 
+  		  DeclFromScope == DeclFromScopeSpec) {
+      LookupCtx = nullptr;
+  		SS = nullptr;
+    } else if (!LookupCtx-&gt;isDependentContext() &amp;&amp;
         RequireCompleteDeclContext(*SS, LookupCtx))
       return nullptr;
   }

------------------------ clang/lib/Sema/SemaLookup.cpp ------------------------
index d3d4bf27ae72..de7b7fbba9b3 100644
@@ -2695,6 +2695,25 @@ bool Sema::LookupParsedName(LookupResult &amp;R, Scope *S, CXXScopeSpec *SS,
             ObjectType-&gt;castAs&lt;TagType&gt;()-&gt;isBeingDefined()) &amp;&amp;
            "Caller should have completed object type");
   } else if (SS &amp;&amp; SS-&gt;isNotEmpty()) {
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S-&gt;getLookupEntity())
+      DeclFromScope = dyn_cast_or_null&lt;CXXRecordDecl&gt;(S-&gt;getLookupEntity());
+
+    if (SS-&gt;isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null&lt;ClassTemplateSpecializationDecl&gt;(
+ 		      SS-&gt;getScopeRep()-&gt;getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl &amp;&amp; 
+    		  ClassTemplateSpecDecl-&gt;getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl-&gt;
+ 		    getSpecializedTemplate()-&gt;getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat &amp;&amp; DeclFromScope &amp;&amp; 
+  		  DeclFromScope == DeclFromScopeSpec)
+      return LookupName(R, S, AllowBuiltinCreation);
+        
     // This nested-name-specifier occurs after another nested-name-specifier,
     // so long into the context associated with the prior nested-name-specifier.
     if ((DC = computeDeclContext(*SS, EnteringContext))) {

@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2024

@llvm/issue-subscribers-clang-frontend

Author: None (VladimirShchigolev)

Consider the following example: ``` template <int I = 0> struct S { static constexpr int A = I; static constexpr int B = S<>::A; }; static_assert(S<1>::B == 0, "S<1>::B should be 0"); ```

Latest MSVC (14.41) is able to compile this:

C:\test&gt;cl.exe /c example.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.41.34120 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

example.cpp

However clang-cl fails to compile:

C:\test&gt;clang-cl.exe example.cpp
C:\test\example.cpp(4,30): error: implicit instantiation of
	  template 'S&lt;&gt;' within its own definition
	4 |     static constexpr int B = S&lt;&gt;::A;
	  |                              ^
C:\test\example.cpp(4,26): error: constexpr variable 'B' must
	  be initialized by a constant expression
	4 |     static constexpr int B = S&lt;&gt;::A;
	  |                          ^
	  |                            = 0
2 errors generated.

Here is a draft patch that I tried to make while working at #47033. It does not work - it removes the errors, but the assert fails. Maybe it will help.

Parent: 520ddf22b2270dc092dbdbd391b1c02c403b475a ([TableGen] Remove duplicate code in applyMnemonicAliases when target uses DefaultAsmParserVariant. (#<!-- -->108494))

------------------------- clang/lib/Sema/SemaDecl.cpp -------------------------
index 3c6a0dff798f..6a12ed82894d 100644
@@ -352,7 +352,26 @@ ParsedType Sema::getTypeName(const IdentifierInfo &amp;II, SourceLocation NameLoc,
       return nullptr;
     }
 
-    if (!LookupCtx-&gt;isDependentContext() &amp;&amp;
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S-&gt;getLookupEntity())
+      DeclFromScope = dyn_cast_or_null&lt;CXXRecordDecl&gt;(S-&gt;getLookupEntity());
+
+    if (SS-&gt;isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null&lt;ClassTemplateSpecializationDecl&gt;(
+ 		      SS-&gt;getScopeRep()-&gt;getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl &amp;&amp; 
+    		  ClassTemplateSpecDecl-&gt;getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl-&gt;
+ 		    getSpecializedTemplate()-&gt;getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat &amp;&amp; DeclFromScope &amp;&amp; 
+  		  DeclFromScope == DeclFromScopeSpec) {
+      LookupCtx = nullptr;
+  		SS = nullptr;
+    } else if (!LookupCtx-&gt;isDependentContext() &amp;&amp;
         RequireCompleteDeclContext(*SS, LookupCtx))
       return nullptr;
   }

------------------------ clang/lib/Sema/SemaLookup.cpp ------------------------
index d3d4bf27ae72..de7b7fbba9b3 100644
@@ -2695,6 +2695,25 @@ bool Sema::LookupParsedName(LookupResult &amp;R, Scope *S, CXXScopeSpec *SS,
             ObjectType-&gt;castAs&lt;TagType&gt;()-&gt;isBeingDefined()) &amp;&amp;
            "Caller should have completed object type");
   } else if (SS &amp;&amp; SS-&gt;isNotEmpty()) {
+    CXXRecordDecl *DeclFromScope = nullptr, *DeclFromScopeSpec = nullptr;
+    if (S-&gt;getLookupEntity())
+      DeclFromScope = dyn_cast_or_null&lt;CXXRecordDecl&gt;(S-&gt;getLookupEntity());
+
+    if (SS-&gt;isValid()) {
+ 	    auto ClassTemplateSpecDecl = 
+ 	        dyn_cast_or_null&lt;ClassTemplateSpecializationDecl&gt;(
+ 		      SS-&gt;getScopeRep()-&gt;getAsRecordDecl());
+  	  if (ClassTemplateSpecDecl &amp;&amp; 
+    		  ClassTemplateSpecDecl-&gt;getSpecializedTemplate()) {
+        DeclFromScopeSpec = ClassTemplateSpecDecl-&gt;
+ 		    getSpecializedTemplate()-&gt;getTemplatedDecl();
+  	  }
+    }
+	
+    if (getLangOpts().MSVCCompat &amp;&amp; DeclFromScope &amp;&amp; 
+  		  DeclFromScope == DeclFromScopeSpec)
+      return LookupName(R, S, AllowBuiltinCreation);
+        
     // This nested-name-specifier occurs after another nested-name-specifier,
     // so long into the context associated with the prior nested-name-specifier.
     if ((DC = computeDeclContext(*SS, EnteringContext))) {

@EugeneZelenko EugeneZelenko added constexpr Anything related to constant evaluation and removed new issue clang-cl `clang-cl` driver. Don't use for other compiler parts labels Sep 17, 2024
@safocl
Copy link

safocl commented Jan 12, 2025

static constexpr int B = S<>::A;

static constexpr int B = S::A;
<source>:6:15: error: static assertion failed due to requirement 'S<1>::B == 0': S<1>::B should be 0
    6 | static_assert(S<1>::B == 0, "S<1>::B should be 0");
      |               ^~~~~~~~~~~~
<source>:6:23: note: expression evaluates to '1 == 0'
    6 | static_assert(S<1>::B == 0, "S<1>::B should be 0");
      |               ~~~~~~~~^~~~
1 error generated.
Compiler returned: 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ clang:frontend Language frontend issues, e.g. anything involving "Sema" constexpr Anything related to constant evaluation
Projects
None yet
Development

No branches or pull requests

5 participants