Skip to content

[Clang] Fix dependency of SourceLocExpr. #78436

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

Merged
merged 2 commits into from
Jan 18, 2024
Merged

[Clang] Fix dependency of SourceLocExpr. #78436

merged 2 commits into from
Jan 18, 2024

Conversation

cor3ntin
Copy link
Contributor

SourceLocExpr that may produce a function name
are marked dependent so that the non-instantiated
name of a function does not get evaluated.

In GH78128, the name('s size) is used as
template argument to a DeclRef that is not otherwise
dependent, and therefore cached and not transformed when the function is instantiated, leading
to 2 different values existing at the same time for the same function.

Fixes #78128

SourceLocExpr that may produce a function name
are marked dependent so that the non-instantiated
name of a function does not get evaluated.

In GH78128, the name('s size) is used as
template argument to a Declref that is not
dependent, and therefore not transformed and cached
when the function is instantiated, leading
to 2 different values existing at the same time
for the same function.

Fixes llvm#78128
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 17, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 17, 2024

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

Changes

SourceLocExpr that may produce a function name
are marked dependent so that the non-instantiated
name of a function does not get evaluated.

In GH78128, the name('s size) is used as
template argument to a DeclRef that is not otherwise
dependent, and therefore cached and not transformed when the function is instantiated, leading
to 2 different values existing at the same time for the same function.

Fixes #78128


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

5 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+4)
  • (modified) clang/include/clang/AST/Expr.h (+11)
  • (modified) clang/lib/AST/Expr.cpp (+4-1)
  • (modified) clang/lib/Sema/TreeTransform.h (+1-1)
  • (modified) clang/test/SemaCXX/source_location.cpp (+27)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 174392da17551ea..a18596097ecd4df 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -913,6 +913,10 @@ Bug Fixes to C++ Support
   (`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
   (`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)
 
+- Fix a bug where clang would produce inconsistent values when
+  std::source_location::current was used in function templates.
+  Fixes  (`#78128 <https://github.com/llvm/llvm-project/issues/78128>`_)
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index a41f2d66b37b69d..8bce87fa7a46eb2 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -4806,6 +4806,17 @@ class SourceLocExpr final : public Expr {
     return T->getStmtClass() == SourceLocExprClass;
   }
 
+  static bool MayBeDependent(SourceLocIdentKind Kind) {
+    switch (Kind) {
+    case SourceLocIdentKind::Function:
+    case SourceLocIdentKind::FuncSig:
+    case SourceLocIdentKind::SourceLocStruct:
+      return true;
+    default:
+      return false;
+    }
+  }
+
 private:
   friend class ASTStmtReader;
 };
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index a90f92d07f86d26..11697a07b0e3228 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2282,7 +2282,10 @@ SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, SourceLocIdentKind Kind,
     : Expr(SourceLocExprClass, ResultTy, VK_PRValue, OK_Ordinary),
       BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) {
   SourceLocExprBits.Kind = llvm::to_underlying(Kind);
-  setDependence(ExprDependence::None);
+  // In dependent contexts, function names may change.
+  setDependence(MayBeDependent(Kind) && ParentContext->isDependentContext()
+                    ? ExprDependence::Value
+                    : ExprDependence::None);
 }
 
 StringRef SourceLocExpr::getBuiltinStr() const {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1a1bc87d2b3203c..4463904b07211bd 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12148,7 +12148,7 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
 
 template <typename Derived>
 ExprResult TreeTransform<Derived>::TransformSourceLocExpr(SourceLocExpr *E) {
-  bool NeedRebuildFunc = E->getIdentKind() == SourceLocIdentKind::Function &&
+  bool NeedRebuildFunc = SourceLocExpr::MayBeDependent(E->getIdentKind()) &&
                          getSema().CurContext != E->getParentContext();
 
   if (!getDerived().AlwaysRebuild() && !NeedRebuildFunc)
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index e92fb35b653a8f3..7414fbce7828d15 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -805,3 +805,30 @@ static_assert(S(0).j == S{0}.j);
 static_assert(S(0).j == S{0}.i);
 }
 #endif
+
+namespace GH78128 {
+
+template<int N>
+constexpr int f() {
+  return N;
+}
+
+template<typename T>
+void foo() {
+  constexpr auto* F1 = std::source_location::current().function();
+  static_assert(__builtin_strlen(F1) == f<__builtin_strlen(F1)>());
+
+  constexpr auto* F2 = __builtin_FUNCTION();
+  static_assert(__builtin_strlen(F2) == f<__builtin_strlen(F2)>());
+
+#ifdef MS
+  constexpr auto* F3 = __builtin_FUNCSIG();
+  static_assert(__builtin_strlen(F3) == f<__builtin_strlen(F3)>());
+#endif
+}
+
+void test() {
+  foo<int>();
+}
+
+}

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

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

LGTM aside from some nits with the release note.

@@ -913,6 +913,10 @@ Bug Fixes to C++ Support
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)

- Fix a bug where clang would produce inconsistent values when
std::source_location::current was used in function templates.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
std::source_location::current was used in function templates.
``std::source_location::current()`` was used in a function template.

@@ -913,6 +913,10 @@ Bug Fixes to C++ Support
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)

- Fix a bug where clang would produce inconsistent values when
std::source_location::current was used in function templates.
Fixes (`#78128 <https://github.com/llvm/llvm-project/issues/78128>`_)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Fixes (`#78128 <https://github.com/llvm/llvm-project/issues/78128>`_)
Fixes (`#78128 <https://github.com/llvm/llvm-project/issues/78128>`_)

@cor3ntin cor3ntin merged commit 8c2b0d4 into llvm:main Jan 18, 2024
ampandey-1995 pushed a commit to ampandey-1995/llvm-project that referenced this pull request Jan 19, 2024
SourceLocExpr that may produce a function name are marked dependent so that the non-instantiated
name of a function does not get evaluated.

In GH78128, the name('s size) is used as
template argument to a `DeclRef` that is not otherwise dependent, and therefore cached and not transformed when the function is
instantiated, leading to 2 different values existing at the same time for the same function.

Fixes llvm#78128
cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Sep 1, 2024
In llvm#78436 we made some SourceLocExpr dependent to
deal with the fact that their value should reflect the name of
specialized function - rather than the rtemplate in which they
are first used.

However SourceLocExpr are unusual in two ways
 - They don't depend on template argumente
 - They morally depend on the context in which they are used
   (rather than called from).

It's fair to say that this is quite novels and confuses
clang. In particular, in some cases, we used to create
dependent SourceLocExpr and never subsequently transform them,
leaving dependent objects in instantiated functions types.
To work around that we avoid replacing SourceLocExpr when we think
they could remain dependent.
It's certainly not perfect but it fixes a number of reported bugs,
and seem to only affect scenarios in which the value of the
SourceLocExpr does not matter (overload resolution).

Fixes llvm#106428
Fixes llvm#81155
cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Sep 2, 2024
In llvm#78436 we made some SourceLocExpr dependent to
deal with the fact that their value should reflect the name of
specialized function - rather than the rtemplate in which they
are first used.

However SourceLocExpr are unusual in two ways
 - They don't depend on template argumente
 - They morally depend on the context in which they are used
   (rather than called from).

It's fair to say that this is quite novels and confuses
clang. In particular, in some cases, we used to create
dependent SourceLocExpr and never subsequently transform them,
leaving dependent objects in instantiated functions types.
To work around that we avoid replacing SourceLocExpr when we think
they could remain dependent.
It's certainly not perfect but it fixes a number of reported bugs,
and seem to only affect scenarios in which the value of the
SourceLocExpr does not matter (overload resolution).

Fixes llvm#106428
Fixes llvm#81155
cor3ntin added a commit that referenced this pull request Sep 4, 2024
In #78436 we made some SourceLocExpr dependent to
deal with the fact that their value should reflect the name of
specialized function - rather than the rtemplate in which they are first
used.

However SourceLocExpr are unusual in two ways
 - They don't depend on template arguments
- They morally depend on the context in which they are used (rather than
called from).

It's fair to say that this is quite novels and confuses clang. In
particular, in some cases, we used to create dependent SourceLocExpr and
never subsequently transform them, leaving dependent objects in
instantiated functions types. To work around that we avoid replacing
SourceLocExpr when we think they could remain dependent.
It's certainly not perfect but it fixes a number of reported bugs, and
seem to only affect scenarios in which the value of the SourceLocExpr
does not matter (overload resolution).

Fixes #106428
Fixes #81155
Fixes #80210
Fixes #85373

---------

Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
cor3ntin added a commit to cor3ntin/llvm-project that referenced this pull request Sep 4, 2024
In llvm#78436 we made some SourceLocExpr dependent to
deal with the fact that their value should reflect the name of
specialized function - rather than the rtemplate in which they are first
used.

However SourceLocExpr are unusual in two ways
 - They don't depend on template arguments
- They morally depend on the context in which they are used (rather than
called from).

It's fair to say that this is quite novels and confuses clang. In
particular, in some cases, we used to create dependent SourceLocExpr and
never subsequently transform them, leaving dependent objects in
instantiated functions types. To work around that we avoid replacing
SourceLocExpr when we think they could remain dependent.
It's certainly not perfect but it fixes a number of reported bugs, and
seem to only affect scenarios in which the value of the SourceLocExpr
does not matter (overload resolution).

Fixes llvm#106428
Fixes llvm#81155
Fixes llvm#80210
Fixes llvm#85373

---------

Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
tru pushed a commit to cor3ntin/llvm-project that referenced this pull request Sep 10, 2024
In llvm#78436 we made some SourceLocExpr dependent to
deal with the fact that their value should reflect the name of
specialized function - rather than the rtemplate in which they are first
used.

However SourceLocExpr are unusual in two ways
 - They don't depend on template arguments
- They morally depend on the context in which they are used (rather than
called from).

It's fair to say that this is quite novels and confuses clang. In
particular, in some cases, we used to create dependent SourceLocExpr and
never subsequently transform them, leaving dependent objects in
instantiated functions types. To work around that we avoid replacing
SourceLocExpr when we think they could remain dependent.
It's certainly not perfect but it fixes a number of reported bugs, and
seem to only affect scenarios in which the value of the SourceLocExpr
does not matter (overload resolution).

Fixes llvm#106428
Fixes llvm#81155
Fixes llvm#80210
Fixes llvm#85373

---------

Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
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.

std::source_location make constexpr size wrong at compile time.
3 participants