Skip to content

[clang] SourceLocIdentKind::Function should not be dependent #94942

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

Closed
wants to merge 1 commit into from

Conversation

jcsxky
Copy link
Contributor

@jcsxky jcsxky commented Jun 10, 2024

Consider the testcase, return type of construct_at is

DecltypeType 0x55555570d8c0 'decltype(new struct BasicPersistent(declval<struct __alloc_traits>()))' sugar dependent
|-CXXNewExpr 0x55555570d880 'struct BasicPersistent *' Function 0x55555570ace0 'operator new' 'void *(unsigned long)'
| `-CXXConstructExpr 0x55555570d848 'struct BasicPersistent' 'void (BasicPersistent &&, SourceLocation)'
|   |-CallExpr 0x55555570aae8 'BasicPersistent':'struct BasicPersistent' xvalue
|   | `-ImplicitCastExpr 0x55555570aad0 'auto (*)(void) -> decltype(__declval<struct __alloc_traits>(0))' <FunctionToPointerDecay>
|   |   `-DeclRefExpr 0x55555570aa18 'auto (void) -> decltype(__declval<struct __alloc_traits>(0))' lvalue Function 0x55555570a908 'declval' 'auto (void) -> decltype(__declval<struct __alloc_traits>(0))' (FunctionTemplate 0x5555556d0548 'declval') non_odr_use_unevaluated
|   `-CXXDefaultArgExpr 0x55555570d820 'SourceLocation':'struct SourceLocation' has rewritten init
|     `-CallExpr 0x55555570d7b0 'SourceLocation':'struct SourceLocation'
|       |-ImplicitCastExpr 0x55555570d798 'SourceLocation (*)(const char *)' <FunctionToPointerDecay>
|       | `-DeclRefExpr 0x5555556fe5c8 'SourceLocation (const char *)' lvalue CXXMethod 0x5555556fdb28 'Current' 'SourceLocation (const char *)'
|       |   `-NestedNameSpecifier TypeSpec 'struct SourceLocation'
|       `-CXXDefaultArgExpr 0x55555570d7f8 'const char *' has rewritten init
|         `-SourceLocExpr 0x55555570d7d8 'const char *'
`-PointerType 0x555555704800 'struct BasicPersistent *'
  `-SubstTemplateTypeParmType 0x5555557047d0 'struct BasicPersistent' sugar typename depth 0 index 0 _Tp
    |-FunctionTemplate 0x5555556ee048 'construct_at'
    `-RecordType 0x5555556cfd10 'struct BasicPersistent'
      `-CXXRecord 0x5555556fdc98 'BasicPersistent'

when in the process of instantiation. This type is dependent due to the dependency of SourceLocExpr which leads to the crash(only crash in codegen stage and clang-check -ast-dump is OK). SourceLocExpr is created in a dependent context when transforming the return type of construct_at because its context(Sema.CurContext) is a dependent FunctionDecl. But SourceLocExpr should not be dependent when we finish the transformation. Removing SourceLocIdentKind::Function makes SourceLocExpr independent.
attempt to fix #80210

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 10, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 10, 2024

@llvm/pr-subscribers-clang

Author: Qizhi Hu (jcsxky)

Changes

Consider the testcase, return type of construct_at is

DecltypeType 0x55555570d8c0 'decltype(new struct BasicPersistent(declval&lt;struct __alloc_traits&gt;()))' sugar dependent
|-CXXNewExpr 0x55555570d880 'struct BasicPersistent *' Function 0x55555570ace0 'operator new' 'void *(unsigned long)'
| `-CXXConstructExpr 0x55555570d848 'struct BasicPersistent' 'void (BasicPersistent &amp;&amp;, SourceLocation)'
|   |-CallExpr 0x55555570aae8 'BasicPersistent':'struct BasicPersistent' xvalue
|   | `-ImplicitCastExpr 0x55555570aad0 'auto (*)(void) -&gt; decltype(__declval&lt;struct __alloc_traits&gt;(0))' &lt;FunctionToPointerDecay&gt;
|   |   `-DeclRefExpr 0x55555570aa18 'auto (void) -&gt; decltype(__declval&lt;struct __alloc_traits&gt;(0))' lvalue Function 0x55555570a908 'declval' 'auto (void) -&gt; decltype(__declval&lt;struct __alloc_traits&gt;(0))' (FunctionTemplate 0x5555556d0548 'declval') non_odr_use_unevaluated
|   `-CXXDefaultArgExpr 0x55555570d820 'SourceLocation':'struct SourceLocation' has rewritten init
|     `-CallExpr 0x55555570d7b0 'SourceLocation':'struct SourceLocation'
|       |-ImplicitCastExpr 0x55555570d798 'SourceLocation (*)(const char *)' &lt;FunctionToPointerDecay&gt;
|       | `-DeclRefExpr 0x5555556fe5c8 'SourceLocation (const char *)' lvalue CXXMethod 0x5555556fdb28 'Current' 'SourceLocation (const char *)'
|       |   `-NestedNameSpecifier TypeSpec 'struct SourceLocation'
|       `-CXXDefaultArgExpr 0x55555570d7f8 'const char *' has rewritten init
|         `-SourceLocExpr 0x55555570d7d8 'const char *'
`-PointerType 0x555555704800 'struct BasicPersistent *'
  `-SubstTemplateTypeParmType 0x5555557047d0 'struct BasicPersistent' sugar typename depth 0 index 0 _Tp
    |-FunctionTemplate 0x5555556ee048 'construct_at'
    `-RecordType 0x5555556cfd10 'struct BasicPersistent'
      `-CXXRecord 0x5555556fdc98 'BasicPersistent'

when in the process of instantiation. This type is dependent due to the dependency of SourceLocExpr which leads to the crash(only crash in codegen stage and clang-check -ast-dump is OK). SourceLocExpr is created in a dependent context when transforming the return type of construct_at because its context(Sema.CurContext) is a dependent FunctionDecl. But SourceLocExpr should not be dependent when we finish the transformation. Removing SourceLocIdentKind::Function makes SourceLocExpr independent.
attempt to fix #80210


Full diff: https://github.com/llvm/llvm-project/pull/94942.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/include/clang/AST/Expr.h (-1)
  • (added) clang/test/CodeGenCXX/PR80210.cpp (+34)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cf1ba02cbc4b2..efe78139de6fa 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -846,6 +846,7 @@ Bug Fixes to C++ Support
 - Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
 - Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
   (#GH88081), (#GH89496), (#GH90669) and (#GH91633).
+- Fix a crash when SourceLocExpr instantiated in a dependent context. (GH80210).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index f2bf667636dc9..92bd7940bdba9 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4786,7 +4786,6 @@ class SourceLocExpr final : public Expr {
 
   static bool MayBeDependent(SourceLocIdentKind Kind) {
     switch (Kind) {
-    case SourceLocIdentKind::Function:
     case SourceLocIdentKind::FuncSig:
     case SourceLocIdentKind::SourceLocStruct:
       return true;
diff --git a/clang/test/CodeGenCXX/PR80210.cpp b/clang/test/CodeGenCXX/PR80210.cpp
new file mode 100644
index 0000000000000..fdd3beb99209e
--- /dev/null
+++ b/clang/test/CodeGenCXX/PR80210.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o /dev/null -verify -triple %itanium_abi_triple
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o /dev/null -verify -triple %ms_abi_triple
+
+// expected-no-diagnostics
+
+struct BasicPersistent;
+template <typename> BasicPersistent &&__declval(int);
+template <typename _Tp> auto declval() -> decltype(__declval<_Tp>(0));
+template <typename _Tp> _Tp forward;
+template <typename _Tp, typename... _Args>
+auto construct_at(_Tp *, _Args...) -> decltype(new _Tp(declval<_Args>()...)) {return 0;}
+template <typename> struct allocator;
+template <typename> struct allocator_traits;
+template <typename _Tp> struct allocator_traits<allocator<_Tp>> {
+  using pointer = _Tp *;
+  template <typename _Up, typename... _Args>
+  static void construct(_Up __p, _Args...) {
+    construct_at(__p, forward<_Args>...);
+  }
+};
+struct __alloc_traits : allocator_traits<allocator<BasicPersistent>> {
+} push_back___x;
+__alloc_traits::pointer _M_impl_0;
+template <typename... _Args> void emplace_back(_Args...) {
+  __alloc_traits::construct(_M_impl_0, forward<_Args>...);
+}
+struct SourceLocation {
+  static SourceLocation Current(const char * = __builtin_FUNCTION());
+};
+struct BasicPersistent {
+  BasicPersistent(BasicPersistent &&,
+                  SourceLocation = SourceLocation::Current());
+};
+void CFXJSE_EngineAddObjectToUpArray() { emplace_back(push_back___x); }

@@ -846,6 +846,7 @@ Bug Fixes to C++ Support
- Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
- Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
(#GH88081), (#GH89496), (#GH90669) and (#GH91633).
- Fix a crash when SourceLocExpr instantiated in a dependent context. (GH80210).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fix a crash when SourceLocExpr instantiated in a dependent context. (GH80210).
- Fix a crash when SourceLocExpr instantiated in a dependent context. (#GH80210).

@cor3ntin
Copy link
Contributor

SourceLocation needs to be dependent because we want to make the name of the function and any template parameter
refers to the instantiated function rather than that of the function template.
This was changed in #78436

The issue is that SourceLocation then is a dependent expression that does not depend on any parameters and its never re-transformed (hence the crash).

I have so far been unable to find a solution. I wonder if we should attach the template parameters to the source location expression, but that seems a bit involved.

@jcsxky
Copy link
Contributor Author

jcsxky commented Jun 10, 2024

because we want to make the name of the function and any template parameter
refers to the instantiated function rather than that of the function template.

Does that mean we should transform the SourceLocExpr into a certain function name when instantiating if it is __builtin_FUNCTION?

@jcsxky
Copy link
Contributor Author

jcsxky commented Jun 12, 2024

SourceLocation needs to be dependent because we want to make the name of the function and any template parameter refers to the instantiated function rather than that of the function template. This was changed in #78436

The issue is that SourceLocation then is a dependent expression that does not depend on any parameters and its never re-transformed (hence the crash).

I have so far been unable to find a solution. I wonder if we should attach the template parameters to the source location expression, but that seems a bit involved.

I tested this patch locally with the code from #78128 and it works well. I doubt whether we need to make SourceLocation dependent when Kind is SourceLocIdentKind::Function. I don't come up with a testcase that make this patch failed or crash.

@jcsxky
Copy link
Contributor Author

jcsxky commented Jun 14, 2024

struct BasicPersistent;

struct SourceLocation {
  static constexpr const char* Current(const char * func = __builtin_FUNCTION()) {
		return func;
	}
};

template <typename> BasicPersistent &&__declval(int);
template <typename _Tp> auto declval() -> decltype(__declval<_Tp>(0));
template <typename _Tp> _Tp forward;

template <typename _Tp, typename... _Args>
auto construct_at(_Tp *, _Args...) -> decltype(new _Tp(declval<_Args>()...)) {
	constexpr auto *F = SourceLocation::Current();
	static_assert(__builtin_strlen(F) == 12);
	return 0;
}

template <typename> struct allocator;
template <typename> struct allocator_traits;
template <typename _Tp> struct allocator_traits<allocator<_Tp>> {
  using pointer = _Tp *;
  template <typename _Up, typename... _Args>
  static void construct(_Up __p, _Args...) {
    construct_at(__p, forward<_Args>...);
  }
};

struct __alloc_traits : allocator_traits<allocator<BasicPersistent>> {
} push_back___x;

__alloc_traits::pointer _M_impl_0;
template <typename... _Args> void emplace_back(_Args...) {
  __alloc_traits::construct(_M_impl_0, forward<_Args>...);
}

struct BasicPersistent {
  BasicPersistent(BasicPersistent &&,
                  const char* = SourceLocation::Current()) {}
};

void CFXJSE_EngineAddObjectToUpArray() { emplace_back(push_back___x); }

I modify the testcase as above and I think we just need to make dependent if Kind is SourceLocIdentKind::SourceLocStruct. Could you please take another look? @cor3ntin

@cor3ntin
Copy link
Contributor

So, looked into this more.
You are correct that Function needs not be dependent because we only ever show the name of the function unqualified.
However, FunctionSig does.
Here is an example of what we are trying to preserve https://godbolt.org/z/M3eTa8nn5 (the clang 17 behavior was incorrect)

I apologize for not realizing earlier that your change was actually sensible in the case of Function

@zyn0217
Copy link
Contributor

zyn0217 commented Jun 15, 2024

nit: Please rephrase the commit message before you merge this patch. A large piece of AST involving memory addresses is really hard to decipher.

In addition, it would be nice if you can simplify the test case further - it's super unclear why a bunch of templates are there outside of the SourceLocation::Current() - probably one or two is sufficient?

@jcsxky
Copy link
Contributor Author

jcsxky commented Jun 16, 2024

So, looked into this more. You are correct that Function needs not be dependent because we only ever show the name of the function unqualified. However, FunctionSig does. Here is an example of what we are trying to preserve https://godbolt.org/z/M3eTa8nn5 (the clang 17 behavior was incorrect)

I apologize for not realizing earlier that your change was actually sensible in the case of Function

Never mind! After looking into the code a little bit more, FunctionSig indeed needs to be dependent.

template<int N>
constexpr int g() {
  return N;
}

template <typename T>
struct S {
    void f(auto) {
        constexpr const char* F = __builtin_FUNCSIG();
        static_assert(__builtin_strlen(F)==g<__builtin_strlen(F)>());
    }

};

void f(){
	S<int>{}.f(0);
}

However, it still crash when we changed from __builtin_FUNCTION to __builtin_FUNCSIG in the testcase from #80210. The underlying issue is that CurContext is FunctionTemplateDecl which is dependent and we used it as ParentContext of SourceLocExpr when transforming decltype of function construct_at. This makes transformed return type of construct_at dependent which is not what we want. I will close this patch since it doesn't resolve the underlying issue. Thanks for your time for the review! @cor3ntin

@jcsxky jcsxky closed this Jun 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[18 regression] Assertion `!T->isDependentType() && "should not see dependent types here"' failed.
5 participants