-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[clang][bytecode] Allow casts from void* only in std::allocator calls #136714
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
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Otherwise, add the missing diagnostic.
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesOtherwise, add the missing diagnostic. Full diff: https://github.com/llvm/llvm-project/pull/136714.diff 8 Files Affected:
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 866d8e4bf2251..e5300b7cd96a9 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1113,6 +1113,12 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
<< P.toDiagnosticString(S.getASTContext());
return false;
}
+ } else if (BothNonNull && P.isIntegralPointer()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
+ << LHS.toDiagnosticString(S.getASTContext())
+ << RHS.toDiagnosticString(S.getASTContext());
+ return false;
}
}
@@ -2389,7 +2395,18 @@ static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
bool HasValidResult = !Ptr.isZero();
if (HasValidResult) {
- // FIXME: note_constexpr_invalid_void_star_cast
+ if (S.getStdAllocatorCaller("allocate"))
+ return true;
+
+ const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
+ if (S.getLangOpts().CPlusPlus26 &&
+ S.getASTContext().hasSimilarType(Ptr.getType(),
+ E->getType()->getPointeeType()))
+ return true;
+
+ S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
+ << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
+ << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
} else if (!S.getLangOpts().CPlusPlus26) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
@@ -2781,10 +2798,9 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
const T &IntVal = S.Stk.pop<T>();
- if (Desc)
- S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
- << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
- << S.getLangOpts().CPlusPlus;
+ S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
+ << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
+ << S.getLangOpts().CPlusPlus;
S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
return true;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 523e471d3c82c..d8b320ff3ba31 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1526,34 +1526,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
// A call to __operator_new is only valid within std::allocate<>::allocate.
// Walk up the call stack to find the appropriate caller and get the
// element type from it.
- QualType ElemType;
- const CallExpr *NewCall = nullptr;
-
- for (const InterpFrame *F = Frame; F; F = F->Caller) {
- const Function *Func = F->getFunction();
- if (!Func)
- continue;
- const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr("allocate"))
- continue;
-
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
-
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
- TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
- ElemType = TAL[0].getAsType();
- NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
- break;
- }
- }
+ auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate");
if (ElemType.isNull()) {
S.FFDiag(Call, S.getLangOpts().CPlusPlus20
@@ -1655,33 +1628,7 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
return false;
// This is permitted only within a call to std::allocator<T>::deallocate.
- bool DeallocateFrameFound = false;
- for (const InterpFrame *F = Frame; F; F = F->Caller) {
- const Function *Func = F->getFunction();
- if (!Func)
- continue;
- const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr("deallocate"))
- continue;
-
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
-
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
- TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
- DeallocateFrameFound = true;
- break;
- }
- }
-
- if (!DeallocateFrameFound) {
+ if (!S.getStdAllocatorCaller("deallocate")) {
S.FFDiag(Call);
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index 70a2e9b62fc3a..d6e6771f0a04f 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -115,3 +115,33 @@ bool InterpState::maybeDiagnoseDanglingAllocations() {
}
return NoAllocationsLeft;
}
+
+StdAllocatorCaller InterpState::getStdAllocatorCaller(StringRef Name) const {
+ for (const InterpFrame *F = Current; F; F = F->Caller) {
+ const Function *Func = F->getFunction();
+ if (!Func)
+ continue;
+ const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(Name))
+ continue;
+
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
+
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
+ TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
+ QualType ElemType = TAL[0].getAsType();
+ const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
+ return {NewCall, ElemType};
+ }
+ }
+
+ return {};
+}
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 528c1a24e7b05..91e09a911ce37 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -32,6 +32,12 @@ class InterpStack;
class InterpFrame;
class SourceMapper;
+struct StdAllocatorCaller {
+ const Expr *Call = nullptr;
+ QualType AllocType;
+ explicit operator bool() { return Call; }
+};
+
/// Interpreter context.
class InterpState final : public State, public SourceMapper {
public:
@@ -116,6 +122,8 @@ class InterpState final : public State, public SourceMapper {
/// \c true otherwise.
bool maybeDiagnoseDanglingAllocations();
+ StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
+
private:
friend class EvaluationResult;
friend class InterpStateCCOverride;
diff --git a/clang/test/AST/ByteCode/c.c b/clang/test/AST/ByteCode/c.c
index fe47f9cab1c9f..a7b1fe07f6d84 100644
--- a/clang/test/AST/ByteCode/c.c
+++ b/clang/test/AST/ByteCode/c.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic,pedantic-expected,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic,pedantic-ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=expected,all -std=c11 -Wcast-qual %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -triple x86_64-linux -verify=pedantic,pedantic-expected,all -std=c11 -Wcast-qual -pedantic %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=pedantic,pedantic-ref,all -std=c11 -Wcast-qual -pedantic %s
typedef __INTPTR_TYPE__ intptr_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
@@ -231,7 +231,8 @@ int castViaInt[*(int*)(unsigned long)"test"]; // ref-error {{variable length arr
// expected-error {{variable length array}} \
// pedantic-expected-error {{variable length array}}
-const void (*const funcp)(void) = (void*)123; // pedantic-warning {{converts between void pointer and function pointer}}
+const void (*const funcp)(void) = (void*)123; // pedantic-warning {{converts between void pointer and function pointer}} \
+ // pedantic-expected-note {{this conversion is not allowed in a constant expression}}
_Static_assert(funcp == (void*)0, ""); // all-error {{failed due to requirement 'funcp == (void *)0'}} \
// pedantic-warning {{expression is not an integer constant expression}}
_Static_assert(funcp == (void*)123, ""); // pedantic-warning {{equality comparison between function pointer and void pointer}} \
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 4c69517304ea7..004f704145afd 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -191,5 +191,6 @@ namespace DynamicCast {
constexpr S* sptr = &s;
struct Str {
int b : reinterpret_cast<S*>(sptr) == reinterpret_cast<S*>(sptr);
+ int g : (S*)(void*)(sptr) == sptr;
};
}
diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp
index d0ade4f5278b1..ce18a9d473302 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -316,3 +316,9 @@ namespace ZeroSizedArray {
}
static_assert(foo() == 1);
}
+namespace VoidCast {
+ constexpr int a = 12;
+ constexpr const int *b = &a;
+ constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a constant expression}} \
+ // all-note {{cast from 'void *' is not allowed in a constant expression}}
+}
diff --git a/clang/test/AST/ByteCode/cxx26.cpp b/clang/test/AST/ByteCode/cxx26.cpp
index cd6b533065010..cd786b17ca9ab 100644
--- a/clang/test/AST/ByteCode/cxx26.cpp
+++ b/clang/test/AST/ByteCode/cxx26.cpp
@@ -31,3 +31,8 @@ namespace ReplaceableAlloc {
static_assert(foo()); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}
+
+constexpr int a = 12;
+constexpr const int *b = &a;
+constexpr int *f = (int*)(void*)b;
+static_assert(*f == 12);
|
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Otherwise, add the missing diagnostic.