Skip to content

Commit 63a7ed4

Browse files
committed
[clang][Interp] Reject non-literal values
1 parent ca00cec commit 63a7ed4

File tree

5 files changed

+55
-0
lines changed

5 files changed

+55
-0
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3256,6 +3256,9 @@ bool Compiler<Emitter>::visitInitializer(const Expr *E) {
32563256
if (E->containsErrors())
32573257
return this->emitError(E);
32583258

3259+
if (!this->checkLiteralType(E))
3260+
return false;
3261+
32593262
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
32603263
/*NewInitializing=*/true);
32613264
return this->Visit(E);
@@ -4698,6 +4701,17 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
46984701
return this->emitRetVoid(MD);
46994702
}
47004703

4704+
template <class Emitter>
4705+
bool Compiler<Emitter>::checkLiteralType(const Expr *E) {
4706+
if (Ctx.getLangOpts().CPlusPlus23)
4707+
return true;
4708+
4709+
if (!E->isPRValue() || E->getType()->isLiteralType(Ctx.getASTContext()))
4710+
return true;
4711+
4712+
return this->emitCheckLiteralType(E->getType().getTypePtr(), E);
4713+
}
4714+
47014715
template <class Emitter>
47024716
bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
47034717
// Classify the return type.

clang/lib/AST/Interp/Compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
359359
const QualType DerivedType);
360360
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
361361

362+
bool checkLiteralType(const Expr *E);
363+
362364
protected:
363365
/// Variable to storage mapping.
364366
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;

clang/lib/AST/Interp/Interp.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,39 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
29702970
BlockDesc, Source);
29712971
}
29722972

2973+
inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
2974+
assert(T);
2975+
assert(!S.getLangOpts().CPlusPlus23);
2976+
2977+
// C++1y: A constant initializer for an object o [...] may also invoke
2978+
// constexpr constructors for o and its subobjects even if those objects
2979+
// are of non-literal class types.
2980+
//
2981+
// C++11 missed this detail for aggregates, so classes like this:
2982+
// struct foo_t { union { int i; volatile int j; } u; };
2983+
// are not (obviously) initializable like so:
2984+
// __attribute__((__require_constant_initialization__))
2985+
// static const foo_t x = {{0}};
2986+
// because "i" is a subobject with non-literal initialization (due to the
2987+
// volatile member of the union). See:
2988+
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
2989+
// Therefore, we use the C++1y behavior.
2990+
2991+
if (S.EvaluatingDecl)
2992+
return true;
2993+
2994+
if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
2995+
S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl)
2996+
return true;
2997+
2998+
const Expr *E = S.Current->getExpr(OpPC);
2999+
if (S.getLangOpts().CPlusPlus11)
3000+
S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
3001+
else
3002+
S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
3003+
return false;
3004+
}
3005+
29733006
//===----------------------------------------------------------------------===//
29743007
// Read opcode arguments
29753008
//===----------------------------------------------------------------------===//

clang/lib/AST/Interp/Opcodes.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def ArgVarDecl : ArgType { let Name = "const VarDecl*"; }
6767
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
6868
def ArgPrimType : ArgType { let Name = "PrimType"; }
6969
def ArgEnumDecl : ArgType { let Name = "const EnumDecl *"; }
70+
def ArgTypePtr : ArgType { let Name = "const Type *"; }
7071

7172
//===----------------------------------------------------------------------===//
7273
// Classes of types instructions operate on.
@@ -396,6 +397,10 @@ def CheckEnumValue : Opcode {
396397
let HasGroup = 1;
397398
}
398399

400+
def CheckLiteralType : Opcode {
401+
let Args = [ArgTypePtr];
402+
}
403+
399404
// [] -> [Value]
400405
def GetGlobal : AccessOpcode;
401406
def GetGlobalUnchecked : AccessOpcode;

clang/test/SemaCXX/new-delete-0x.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11
2+
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11 -fexperimental-new-constant-interpreter
23

34
using size_t = decltype(sizeof(0));
45
struct noreturn_t {} constexpr noreturn = {};

0 commit comments

Comments
 (0)