mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 10:56:06 +00:00
DR1213: element access on an array xvalue or prvalue produces an xvalue. In the
latter case, a temporary array object is materialized, and can be lifetime-extended by binding a reference to the member access. Likewise, in an array-to-pointer decay, an rvalue array is materialized before being converted into a pointer. This caused IR generation to stop treating file-scope array compound literals as having static storage duration in some cases in C++; that has been rectified by modeling such a compound literal as an lvalue. This also improves clang's compatibility with GCC for those cases. llvm-svn: 288654
This commit is contained in:
parent
215ff84b40
commit
b3189a1802
@ -141,10 +141,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
|||||||
return Cl::CL_LValue;
|
return Cl::CL_LValue;
|
||||||
|
|
||||||
// C99 6.5.2.5p5 says that compound literals are lvalues.
|
// C99 6.5.2.5p5 says that compound literals are lvalues.
|
||||||
// In C++, they're prvalue temporaries.
|
// In C++, they're prvalue temporaries, except for file-scope arrays.
|
||||||
case Expr::CompoundLiteralExprClass:
|
case Expr::CompoundLiteralExprClass:
|
||||||
return Ctx.getLangOpts().CPlusPlus ? ClassifyTemporary(E->getType())
|
return !E->isLValue() ? ClassifyTemporary(E->getType()) : Cl::CL_LValue;
|
||||||
: Cl::CL_LValue;
|
|
||||||
|
|
||||||
// Expressions that are prvalues.
|
// Expressions that are prvalues.
|
||||||
case Expr::CXXBoolLiteralExprClass:
|
case Expr::CXXBoolLiteralExprClass:
|
||||||
@ -196,11 +195,20 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
|||||||
return ClassifyInternal(Ctx,
|
return ClassifyInternal(Ctx,
|
||||||
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
|
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
|
||||||
|
|
||||||
// C++ [expr.sub]p1: The result is an lvalue of type "T".
|
// C, C++98 [expr.sub]p1: The result is an lvalue of type "T".
|
||||||
// However, subscripting vector types is more like member access.
|
// C++11 (DR1213): in the case of an array operand, the result is an lvalue
|
||||||
|
// if that operand is an lvalue and an xvalue otherwise.
|
||||||
|
// Subscripting vector types is more like member access.
|
||||||
case Expr::ArraySubscriptExprClass:
|
case Expr::ArraySubscriptExprClass:
|
||||||
if (cast<ArraySubscriptExpr>(E)->getBase()->getType()->isVectorType())
|
if (cast<ArraySubscriptExpr>(E)->getBase()->getType()->isVectorType())
|
||||||
return ClassifyInternal(Ctx, cast<ArraySubscriptExpr>(E)->getBase());
|
return ClassifyInternal(Ctx, cast<ArraySubscriptExpr>(E)->getBase());
|
||||||
|
if (Lang.CPlusPlus11) {
|
||||||
|
// Step over the array-to-pointer decay if present, but not over the
|
||||||
|
// temporary materialization.
|
||||||
|
auto *Base = cast<ArraySubscriptExpr>(E)->getBase()->IgnoreImpCasts();
|
||||||
|
if (Base->getType()->isArrayType())
|
||||||
|
return ClassifyInternal(Ctx, Base);
|
||||||
|
}
|
||||||
return Cl::CL_LValue;
|
return Cl::CL_LValue;
|
||||||
|
|
||||||
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
|
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
|
||||||
|
@ -2907,7 +2907,6 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
|
|||||||
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
|
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
|
||||||
// initializer until now for such expressions. Such an expression can't be
|
// initializer until now for such expressions. Such an expression can't be
|
||||||
// an ICE in C, so this only matters for fold.
|
// an ICE in C, so this only matters for fold.
|
||||||
assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
|
|
||||||
if (Type.isVolatileQualified()) {
|
if (Type.isVolatileQualified()) {
|
||||||
Info.FFDiag(Conv);
|
Info.FFDiag(Conv);
|
||||||
return false;
|
return false;
|
||||||
@ -4711,7 +4710,7 @@ public:
|
|||||||
// * VarDecl
|
// * VarDecl
|
||||||
// * FunctionDecl
|
// * FunctionDecl
|
||||||
// - Literals
|
// - Literals
|
||||||
// * CompoundLiteralExpr in C
|
// * CompoundLiteralExpr in C (and in global scope in C++)
|
||||||
// * StringLiteral
|
// * StringLiteral
|
||||||
// * CXXTypeidExpr
|
// * CXXTypeidExpr
|
||||||
// * PredefinedExpr
|
// * PredefinedExpr
|
||||||
@ -4906,7 +4905,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
||||||
assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
|
assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) &&
|
||||||
|
"lvalue compound literal in c++?");
|
||||||
// Defer visiting the literal until the lvalue-to-rvalue conversion. We can
|
// Defer visiting the literal until the lvalue-to-rvalue conversion. We can
|
||||||
// only see this when folding in C, so there's no standard to follow here.
|
// only see this when folding in C, so there's no standard to follow here.
|
||||||
return Success(E);
|
return Success(E);
|
||||||
|
@ -390,6 +390,18 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
|
|||||||
if (ExprTy == TypeTy)
|
if (ExprTy == TypeTy)
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
|
// C++1z [conv.array]: The temporary materialization conversion is applied.
|
||||||
|
// We also use this to fuel C++ DR1213, which applies to C++11 onwards.
|
||||||
|
if (Kind == CK_ArrayToPointerDecay && getLangOpts().CPlusPlus &&
|
||||||
|
E->getValueKind() == VK_RValue) {
|
||||||
|
// The temporary is an lvalue in C++98 and an xvalue otherwise.
|
||||||
|
ExprResult Materialized = CreateMaterializeTemporaryExpr(
|
||||||
|
E->getType(), E, !getLangOpts().CPlusPlus11);
|
||||||
|
if (Materialized.isInvalid())
|
||||||
|
return ExprError();
|
||||||
|
E = Materialized.get();
|
||||||
|
}
|
||||||
|
|
||||||
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
|
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) {
|
||||||
if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
|
if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) {
|
||||||
ImpCast->setType(Ty);
|
ImpCast->setType(Ty);
|
||||||
|
@ -4376,6 +4376,16 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
|
|||||||
Expr *LHSExp = Base;
|
Expr *LHSExp = Base;
|
||||||
Expr *RHSExp = Idx;
|
Expr *RHSExp = Idx;
|
||||||
|
|
||||||
|
ExprValueKind VK = VK_LValue;
|
||||||
|
ExprObjectKind OK = OK_Ordinary;
|
||||||
|
|
||||||
|
// Per C++ core issue 1213, the result is an xvalue if either operand is
|
||||||
|
// a non-lvalue array, and an lvalue otherwise.
|
||||||
|
if (getLangOpts().CPlusPlus11 &&
|
||||||
|
((LHSExp->getType()->isArrayType() && !LHSExp->isLValue()) ||
|
||||||
|
(RHSExp->getType()->isArrayType() && !RHSExp->isLValue())))
|
||||||
|
VK = VK_XValue;
|
||||||
|
|
||||||
// Perform default conversions.
|
// Perform default conversions.
|
||||||
if (!LHSExp->getType()->getAs<VectorType>()) {
|
if (!LHSExp->getType()->getAs<VectorType>()) {
|
||||||
ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp);
|
ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp);
|
||||||
@ -4389,8 +4399,6 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
|
|||||||
RHSExp = Result.get();
|
RHSExp = Result.get();
|
||||||
|
|
||||||
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
|
QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType();
|
||||||
ExprValueKind VK = VK_LValue;
|
|
||||||
ExprObjectKind OK = OK_Ordinary;
|
|
||||||
|
|
||||||
// C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent
|
// C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent
|
||||||
// to the expression *((e1)+(e2)). This means the array "Base" may actually be
|
// to the expression *((e1)+(e2)). This means the array "Base" may actually be
|
||||||
@ -5587,11 +5595,31 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In C, compound literals are l-values for some reason.
|
// In C, compound literals are l-values for some reason.
|
||||||
ExprValueKind VK = getLangOpts().CPlusPlus ? VK_RValue : VK_LValue;
|
// For GCC compatibility, in C++, file-scope array compound literals with
|
||||||
|
// constant initializers are also l-values, and compound literals are
|
||||||
|
// otherwise prvalues.
|
||||||
|
//
|
||||||
|
// (GCC also treats C++ list-initialized file-scope array prvalues with
|
||||||
|
// constant initializers as l-values, but that's non-conforming, so we don't
|
||||||
|
// follow it there.)
|
||||||
|
//
|
||||||
|
// FIXME: It would be better to handle the lvalue cases as materializing and
|
||||||
|
// lifetime-extending a temporary object, but our materialized temporaries
|
||||||
|
// representation only supports lifetime extension from a variable, not "out
|
||||||
|
// of thin air".
|
||||||
|
// FIXME: For C++, we might want to instead lifetime-extend only if a pointer
|
||||||
|
// is bound to the result of applying array-to-pointer decay to the compound
|
||||||
|
// literal.
|
||||||
|
// FIXME: GCC supports compound literals of reference type, which should
|
||||||
|
// obviously have a value kind derived from the kind of reference involved.
|
||||||
|
ExprValueKind VK =
|
||||||
|
(getLangOpts().CPlusPlus && !(isFileScope && literalType->isArrayType()))
|
||||||
|
? VK_RValue
|
||||||
|
: VK_LValue;
|
||||||
|
|
||||||
return MaybeBindToTemporary(
|
return MaybeBindToTemporary(
|
||||||
new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
|
new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
|
||||||
VK, LiteralExpr, isFileScope));
|
VK, LiteralExpr, isFileScope));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
|
@ -5971,9 +5971,10 @@ performReferenceExtension(Expr *Init,
|
|||||||
if (CE->getSubExpr()->isGLValue())
|
if (CE->getSubExpr()->isGLValue())
|
||||||
Init = CE->getSubExpr();
|
Init = CE->getSubExpr();
|
||||||
|
|
||||||
// FIXME: Per DR1213, subscripting on an array temporary produces an xvalue.
|
// Per the current approach for DR1299, look through array element access
|
||||||
// It's unclear if binding a reference to that xvalue extends the array
|
// when performing lifetime extension.
|
||||||
// temporary.
|
if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init))
|
||||||
|
Init = ASE->getBase();
|
||||||
} while (Init != Old);
|
} while (Init != Old);
|
||||||
|
|
||||||
if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
|
if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
|
||||||
|
@ -480,15 +480,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
|
|||||||
Loc CLLoc = State->getLValue(CL, LCtx);
|
Loc CLLoc = State->getLValue(CL, LCtx);
|
||||||
State = State->bindLoc(CLLoc, V);
|
State = State->bindLoc(CLLoc, V);
|
||||||
|
|
||||||
// Compound literal expressions are a GNU extension in C++.
|
if (CL->isGLValue())
|
||||||
// Unlike in C, where CLs are lvalues, in C++ CLs are prvalues,
|
|
||||||
// and like temporary objects created by the functional notation T()
|
|
||||||
// CLs are destroyed at the end of the containing full-expression.
|
|
||||||
// HOWEVER, an rvalue of array type is not something the analyzer can
|
|
||||||
// reason about, since we expect all regions to be wrapped in Locs.
|
|
||||||
// So we treat array CLs as lvalues as well, knowing that they will decay
|
|
||||||
// to pointers as soon as they are used.
|
|
||||||
if (CL->isGLValue() || CL->getType()->isArrayType())
|
|
||||||
V = CLLoc;
|
V = CLLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ void test_4(int x, int y) {
|
|||||||
clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}}
|
clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}}
|
||||||
clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}}
|
clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}}
|
||||||
clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}}
|
clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}}
|
||||||
clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of compound literal \(int \[3\]\)\{1, 2, 3\}$}}}}
|
clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of temporary object constructed at statement '\(int \[3\]\)\{1, 2, 3\}'$}}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -5,6 +5,17 @@
|
|||||||
|
|
||||||
// expected-no-diagnostics
|
// expected-no-diagnostics
|
||||||
|
|
||||||
|
namespace dr1213 { // dr1213: 4.0
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
using T = int[3];
|
||||||
|
int &&r = T{}[1];
|
||||||
|
|
||||||
|
using T = decltype((T{}));
|
||||||
|
using U = decltype((T{}[2]));
|
||||||
|
using U = int &&;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
namespace dr1250 { // dr1250: 3.9
|
namespace dr1250 { // dr1250: 3.9
|
||||||
struct Incomplete;
|
struct Incomplete;
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ struct Y {
|
|||||||
X x;
|
X x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// CHECK: @.compoundliteral = internal global [5 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5], align 4
|
||||||
|
// CHECK: @q = global i32* getelementptr inbounds ([5 x i32], [5 x i32]* @.compoundliteral, i32 0, i32 0), align 4
|
||||||
|
|
||||||
// CHECK-LABEL: define i32 @_Z1fv()
|
// CHECK-LABEL: define i32 @_Z1fv()
|
||||||
int f() {
|
int f() {
|
||||||
// CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca
|
// CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca
|
||||||
@ -51,20 +54,27 @@ int *p = (Z){ {1, 2, 3} }.i;
|
|||||||
// CHECK: store i32* %{{.*}}, i32** @p
|
// CHECK: store i32* %{{.*}}, i32** @p
|
||||||
|
|
||||||
int *q = (int [5]){1, 2, 3, 4, 5};
|
int *q = (int [5]){1, 2, 3, 4, 5};
|
||||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.1()
|
// (constant initialization, checked above)
|
||||||
// CHECK: store i32* getelementptr inbounds ([5 x i32], [5 x i32]* @.compoundliteral, i32 0, i32 0), i32** @q
|
|
||||||
|
|
||||||
int *PR21912_1 = (int []){};
|
extern int n;
|
||||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.2()
|
int *r = (int [5]){1, 2, 3, 4, 5} + n;
|
||||||
// CHECK: store i32* getelementptr inbounds ([0 x i32], [0 x i32]* @.compoundliteral.3, i32 0, i32 0), i32** @PR21912_1
|
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.1()
|
||||||
|
// CHECK: %[[PTR:.*]] = getelementptr inbounds i32, i32* getelementptr inbounds ([5 x i32], [5 x i32]* @.compoundliteral.2, i32 0, i32 0), i32 %
|
||||||
|
// CHECK: store i32* %[[PTR]], i32** @r
|
||||||
|
|
||||||
|
int *PR21912_1 = (int []){} + n;
|
||||||
|
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.3()
|
||||||
|
// CHECK: %[[PTR:.*]] = getelementptr inbounds i32, i32* getelementptr inbounds ([0 x i32], [0 x i32]* @.compoundliteral.4, i32 0, i32 0), i32 %
|
||||||
|
// CHECK: store i32* %[[PTR]], i32** @PR21912_1
|
||||||
|
|
||||||
union PR21912Ty {
|
union PR21912Ty {
|
||||||
long long l;
|
long long l;
|
||||||
double d;
|
double d;
|
||||||
};
|
};
|
||||||
union PR21912Ty *PR21912_2 = (union PR21912Ty[]){{.d = 2.0}, {.l = 3}};
|
union PR21912Ty *PR21912_2 = (union PR21912Ty[]){{.d = 2.0}, {.l = 3}} + n;
|
||||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.4()
|
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.5()
|
||||||
// CHECK: store %union.PR21912Ty* getelementptr inbounds ([2 x %union.PR21912Ty], [2 x %union.PR21912Ty]* bitcast (<{ { double }, %union.PR21912Ty }>* @.compoundliteral.5 to [2 x %union.PR21912Ty]*), i32 0, i32 0), %union.PR21912Ty** @PR21912_2
|
// CHECK: %[[PTR:.*]] = getelementptr inbounds %union.PR21912Ty, %union.PR21912Ty* getelementptr inbounds ([2 x %union.PR21912Ty], [2 x %union.PR21912Ty]* bitcast (<{ { double }, %union.PR21912Ty }>* @.compoundliteral.6 to [2 x %union.PR21912Ty]*), i32 0, i32 0), i32 %
|
||||||
|
// CHECK: store %union.PR21912Ty* %[[PTR]], %union.PR21912Ty** @PR21912_2, align 4
|
||||||
|
|
||||||
// This compound literal should have local scope.
|
// This compound literal should have local scope.
|
||||||
int computed_with_lambda = [] {
|
int computed_with_lambda = [] {
|
||||||
|
@ -132,8 +132,8 @@ void large_auto_object() {
|
|||||||
|
|
||||||
int large_combiner_test(S_large s) {
|
int large_combiner_test(S_large s) {
|
||||||
// CHECK-LABEL: define i32 @large_combiner_test
|
// CHECK-LABEL: define i32 @large_combiner_test
|
||||||
// CHECK: [[T1:%.*]] = alloca %struct.Combiner
|
|
||||||
// CHECK: [[T2:%.*]] = alloca %struct.Combiner
|
// CHECK: [[T2:%.*]] = alloca %struct.Combiner
|
||||||
|
// CHECK: [[T1:%.*]] = alloca %struct.Combiner
|
||||||
// CHECK: [[T3:%.*]] = call %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce)
|
// CHECK: [[T3:%.*]] = call %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce)
|
||||||
// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]])
|
// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]])
|
||||||
// CHECK: [[T4:%.*]] = getelementptr inbounds %struct.Combiner, %struct.Combiner* [[T2]], i32 0, i32 0, i32 0, i32 0
|
// CHECK: [[T4:%.*]] = getelementptr inbounds %struct.Combiner, %struct.Combiner* [[T2]], i32 0, i32 0, i32 0, i32 0
|
||||||
|
@ -779,6 +779,36 @@ namespace MultipleExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ArrayAccess {
|
||||||
|
struct A { A(int); ~A(); };
|
||||||
|
void g();
|
||||||
|
void f() {
|
||||||
|
using T = A[3];
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 1
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 2
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 3
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
A &&a = T{1, 2, 3}[1];
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 4
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 5
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AC1Ei({{.*}}, i32 6
|
||||||
|
// CHECK-NOT: @_ZN11ArrayAccess1AD
|
||||||
|
A &&b = 2[T{4, 5, 6}];
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1gEv(
|
||||||
|
g();
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AD
|
||||||
|
// CHECK: call void @_ZN11ArrayAccess1AD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace PR14130 {
|
namespace PR14130 {
|
||||||
struct S { S(int); };
|
struct S { S(int); };
|
||||||
struct U { S &&s; };
|
struct U { S &&s; };
|
||||||
|
@ -1467,13 +1467,26 @@ namespace VLASizeof {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace CompoundLiteral {
|
namespace CompoundLiteral {
|
||||||
// FIXME:
|
// Matching GCC, file-scope array compound literals initialized by constants
|
||||||
// We don't model the semantics of this correctly: the compound literal is
|
// are lifetime-extended.
|
||||||
// represented as a prvalue in the AST, but actually behaves like an lvalue.
|
constexpr int *p = (int*)(int[1]){3}; // expected-warning {{C99}}
|
||||||
// We treat the compound literal as a temporary and refuse to produce a
|
static_assert(*p == 3, "");
|
||||||
// pointer to it. This is OK: we're not required to treat this as a constant
|
static_assert((int[2]){1, 2}[1] == 2, ""); // expected-warning {{C99}}
|
||||||
// in C++, and in C we model compound literals as lvalues.
|
|
||||||
constexpr int *p = (int*)(int[1]){0}; // expected-warning {{C99}} expected-error {{constant expression}} expected-note 2{{temporary}}
|
// Other kinds are not.
|
||||||
|
struct X { int a[2]; };
|
||||||
|
constexpr int *n = (X){1, 2}.a; // expected-warning {{C99}} expected-warning {{temporary array}}
|
||||||
|
// expected-error@-1 {{constant expression}}
|
||||||
|
// expected-note@-2 {{pointer to subobject of temporary}}
|
||||||
|
// expected-note@-3 {{temporary created here}}
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
static constexpr int *p = (int*)(int[1]){3}; // expected-warning {{C99}}
|
||||||
|
// expected-error@-1 {{constant expression}}
|
||||||
|
// expected-note@-2 {{pointer to subobject of temporary}}
|
||||||
|
// expected-note@-3 {{temporary created here}}
|
||||||
|
static_assert((int[2]){1, 2}[1] == 2, ""); // expected-warning {{C99}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Vector {
|
namespace Vector {
|
||||||
|
@ -7093,7 +7093,7 @@ and <I>POD class</I></td>
|
|||||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1213">1213</a></td>
|
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1213">1213</a></td>
|
||||||
<td>CD3</td>
|
<td>CD3</td>
|
||||||
<td>Array subscripting and xvalues</td>
|
<td>Array subscripting and xvalues</td>
|
||||||
<td class="none" align="center">Unknown</td>
|
<td class="svn" align="center">SVN</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="1214">
|
<tr id="1214">
|
||||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1214">1214</a></td>
|
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1214">1214</a></td>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user