Skip to content

Conversation

@tbaederr
Copy link
Contributor

In multiple inheritance/diamond scenarios, we might arrive at the wrong type.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:bytecode Issues for the clang bytecode constexpr interpreter labels May 20, 2025
@llvmbot
Copy link
Member

llvmbot commented May 20, 2025

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

In multiple inheritance/diamond scenarios, we might arrive at the wrong type.


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

4 Files Affected:

  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+6-3)
  • (modified) clang/lib/AST/ByteCode/Interp.h (+19-1)
  • (modified) clang/lib/AST/ByteCode/Opcodes.td (+1-1)
  • (modified) clang/test/AST/ByteCode/records.cpp (+12)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index aa8f009f58bb9..fd2f25d2476c5 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -296,12 +296,15 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
   case CK_BaseToDerived: {
     if (!this->delegate(SubExpr))
       return false;
-
     unsigned DerivedOffset =
         collectBaseOffset(SubExpr->getType(), CE->getType());
 
-    return this->emitGetPtrDerivedPop(
-        DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE);
+    const Type *TargetType = CE->getType().getTypePtr();
+    if (TargetType->isPointerOrReferenceType())
+      TargetType = TargetType->getPointeeType().getTypePtr();
+    return this->emitGetPtrDerivedPop(DerivedOffset,
+                                      /*NullOK=*/CE->getType()->isPointerType(),
+                                      TargetType, CE);
   }
 
   case CK_FloatingCast: {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 9f1a6302eb856..88de615a6dae5 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1643,7 +1643,7 @@ inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
 }
 
 inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
-                             bool NullOK) {
+                             bool NullOK, const Type *TargetType) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
     return false;
@@ -1661,6 +1661,24 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
   if (!CheckDowncast(S, OpPC, Ptr, Off))
     return false;
 
+  const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
+  assert(TargetRecord);
+
+  if (TargetRecord->getDecl()
+          ->getTypeForDecl()
+          ->getAsCXXRecordDecl()
+          ->getCanonicalDecl() !=
+      TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
+    QualType MostDerivedType = Ptr.getDeclDesc()->getType();
+    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
+        << MostDerivedType << QualType(TargetType, 0);
+    return false;
+  }
+
+  // New pointer should be of the requested type.
+  assert(Ptr.atFieldSub(Off).getType()->getUnqualifiedDesugaredType() ==
+         TargetType->getUnqualifiedDesugaredType());
+
   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
   return true;
 }
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 9dddcced8ca38..c8db8da113bd4 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -325,7 +325,7 @@ def GetMemberPtrBasePop : Opcode {
 def FinishInitPop : Opcode;
 def FinishInit    : Opcode;
 
-def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool]; }
+def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }
 
 // [Pointer] -> [Pointer]
 def GetPtrVirtBasePop : Opcode {
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index c2fe3d9007480..9361d6ddeda70 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1830,3 +1830,15 @@ namespace NullDtor {
   static_assert(foo() == 10, ""); // both-error {{not an integral constant expression}} \
                                   // both-note {{in call to}}
 }
+
+namespace DiamondDowncast {
+  struct Top {};
+  struct Middle1 : Top {};
+  struct Middle2 : Top {};
+  struct Bottom : Middle1, Middle2 {};
+
+  constexpr Bottom bottom;
+  constexpr Top &top1 = (Middle1&)bottom;
+  constexpr Middle2 &fail = (Middle2&)top1; // both-error {{must be initialized by a constant expression}} \
+                                            // both-note {{cannot cast object of dynamic type 'const Bottom' to type 'Middle2'}}
+}

In multiple inheritance/diamond scenarios, we might arrive at
the wrong type.
@tbaederr tbaederr merged commit d013556 into llvm:main May 20, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 20, 2025

LLVM Buildbot has detected a new failure on builder fuchsia-x86_64-linux running on fuchsia-debian-64-us-central1-a-1 while building clang at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/11/builds/15505

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/fuchsia-linux.py ...' (failure)
...
[250/2500] Copying CXX header __atomic/to_gcc_order.h
[251/2500] Generating header errno.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/errno.yaml
[252/2500] Generating header uchar.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/uchar.yaml
[253/2500] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.strncasecmp.dir/strncasecmp.cpp.obj
[254/2500] Generating header string.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/string.yaml
[255/2500] Generating header ctype.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/ctype.yaml
[256/2500] Generating header time.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/time.yaml
[257/2500] Generating header setjmp.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/setjmp.yaml
[258/2500] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.bcopy.dir/bcopy.cpp.obj
[259/2500] Building CXX object libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj
FAILED: libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/./bin/clang++ --target=riscv32-unknown-elf -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/include/riscv32-unknown-unknown-elf --target=riscv32-unknown-elf -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" -D_LIBCPP_PRINT=1 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wno-unnecessary-virtual-specifier -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/runtimes/runtimes-riscv32-unknown-elf-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=riscv32-unknown-elf -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -MF libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj.d -o libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp:13:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/libc_assert.h:25:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/integer_to_string.h:70:
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:31: error: use of undeclared identifier 'uint16_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:62: error: use of undeclared identifier 'uint8_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                                                              ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:31: error: use of undeclared identifier 'uint32_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:62: error: use of undeclared identifier 'uint16_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                                                              ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:81:38: error: use of undeclared identifier 'uint8_t'
   81 |   if constexpr (cpp::is_same_v<word, uint8_t>) {
      |                                      ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:82:18: error: use of undeclared identifier 'uint16_t'
   82 |     return split<uint16_t>(uint16_t(a) * uint16_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:83:45: error: use of undeclared identifier 'uint16_t'
   83 |   } else if constexpr (cpp::is_same_v<word, uint16_t>) {
      |                                             ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:84:18: error: use of undeclared identifier 'uint32_t'
   84 |     return split<uint32_t>(uint32_t(a) * uint32_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:332:57: error: unknown type name 'uint64_t'
  332 | template <size_t Bits, bool Signed, typename WordType = uint64_t>
      |                                                         ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:643:36: error: unknown type name 'uint64_t'
  643 |   LIBC_INLINE constexpr void pow_n(uint64_t power) {
      |                                    ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1066:31: error: use of undeclared identifier 'uint32_t'
 1066 |                               uint32_t
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1071:62: error: use of undeclared identifier 'uint16_t'
Step 6 (build) failure: build (failure)
...
[250/2500] Copying CXX header __atomic/to_gcc_order.h
[251/2500] Generating header errno.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/errno.yaml
[252/2500] Generating header uchar.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/uchar.yaml
[253/2500] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.strncasecmp.dir/strncasecmp.cpp.obj
[254/2500] Generating header string.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/string.yaml
[255/2500] Generating header ctype.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/ctype.yaml
[256/2500] Generating header time.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/time.yaml
[257/2500] Generating header setjmp.h from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/runtimes/../libc/include/setjmp.yaml
[258/2500] Building CXX object libc/src/strings/CMakeFiles/libc.src.strings.bcopy.dir/bcopy.cpp.obj
[259/2500] Building CXX object libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj
FAILED: libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/./bin/clang++ --target=riscv32-unknown-elf -DLIBC_NAMESPACE=__llvm_libc_21_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/include/riscv32-unknown-unknown-elf --target=riscv32-unknown-elf -march=rv32imafc -mabi=ilp32f -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" -D_LIBCPP_PRINT=1 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wno-unnecessary-virtual-specifier -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-z98elllf/runtimes/runtimes-riscv32-unknown-elf-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=riscv32-unknown-elf -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -MF libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj.d -o libc/src/stdlib/CMakeFiles/libc.src.stdlib.l64a.dir/l64a.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdlib/l64a.cpp:13:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/libc_assert.h:25:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/integer_to_string.h:70:
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:31: error: use of undeclared identifier 'uint16_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:35:62: error: use of undeclared identifier 'uint8_t'
   35 | template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {};
      |                                                              ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:31: error: use of undeclared identifier 'uint32_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:36:62: error: use of undeclared identifier 'uint16_t'
   36 | template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {};
      |                                                              ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:81:38: error: use of undeclared identifier 'uint8_t'
   81 |   if constexpr (cpp::is_same_v<word, uint8_t>) {
      |                                      ^~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:82:18: error: use of undeclared identifier 'uint16_t'
   82 |     return split<uint16_t>(uint16_t(a) * uint16_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:83:45: error: use of undeclared identifier 'uint16_t'
   83 |   } else if constexpr (cpp::is_same_v<word, uint16_t>) {
      |                                             ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:84:18: error: use of undeclared identifier 'uint32_t'
   84 |     return split<uint32_t>(uint32_t(a) * uint32_t(b));
      |                  ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:332:57: error: unknown type name 'uint64_t'
  332 | template <size_t Bits, bool Signed, typename WordType = uint64_t>
      |                                                         ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:643:36: error: unknown type name 'uint64_t'
  643 |   LIBC_INLINE constexpr void pow_n(uint64_t power) {
      |                                    ^
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1066:31: error: use of undeclared identifier 'uint32_t'
 1066 |                               uint32_t
      |                               ^~~~~~~~
/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/__support/big_int.h:1071:62: error: use of undeclared identifier 'uint16_t'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:bytecode Issues for the clang bytecode constexpr interpreter 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.

3 participants