CharUnits Alignment = getContext().getDeclAlign(ND);
QualType T = E->getType();
+ // A DeclRefExpr for a reference initialized by a constant expression can
+ // appear without being odr-used. Directly emit the constant initializer.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ const Expr *Init = VD->getAnyInitializer(VD);
+ if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() &&
+ VD->isUsableInConstantExpressions(getContext()) &&
+ VD->checkInitIsICE()) {
+ llvm::Constant *Val =
+ CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this);
+ assert(Val && "failed to emit reference constant expression");
+ // FIXME: Eventually we will want to emit vector element references.
+ return MakeAddrLValue(Val, T, Alignment);
+ }
+ }
+
// FIXME: We should be able to assert this for FunctionDecls as well!
// FIXME: We should be able to assert this for all DeclRefExprs, not just
// those with a valid source location.
if (ND->hasAttr<WeakRefAttr>()) {
const ValueDecl *VD = cast<ValueDecl>(ND);
llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD);
- return MakeAddrLValue(Aliasee, E->getType(), Alignment);
+ return MakeAddrLValue(Aliasee, T, Alignment);
}
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
}
assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
- CharUnits alignment = getContext().getDeclAlign(VD);
return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable),
- E->getType(), alignment);
+ T, Alignment);
}
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
}
}
- // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
- // an object that satisfies the requirements for appearing in a
- // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
+ // the requirements for appearing in a constant expression (5.19) and, if
+ // it is an object, the lvalue-to-rvalue conversion (4.1)
// is immediately applied." We check the first part here, and
// Sema::UpdateMarkingForLValueToRValue deals with the second part.
// Note that we use the C++11 definition everywhere because nothing in
- // C++03 depends on whether we get the C++03 version correct. This does not
- // apply to references, since they are not objects.
+ // C++03 depends on whether we get the C++03 version correct. The second
+ // part does not apply to references, since they are not objects.
const VarDecl *DefVD;
- if (E && !isa<ParmVarDecl>(Var) && !Var->getType()->isReferenceType() &&
+ if (E && !isa<ParmVarDecl>(Var) &&
Var->isUsableInConstantExpressions(SemaRef.Context) &&
- Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE())
- SemaRef.MaybeODRUseExprs.insert(E);
- else
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {
+ if (!Var->getType()->isReferenceType())
+ SemaRef.MaybeODRUseExprs.insert(E);
+ } else
MarkVarDeclODRUsed(SemaRef, Var, Loc);
}
// CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
consume<const S&>(s);
- // FIXME CHECK-NOT: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
- // There's no lvalue-to-rvalue conversion here, so 'r' is odr-used, and
- // we're permitted to emit a load of it. This seems likely to be a defect
- // in the standard. If we start emitting a direct reference to 's', update
- // this test.
+ // CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
consume<const S&>(r);
// CHECK: call void @_ZN13InitFromConst7consumeIPKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE)
// CHECK-NOT: 5begin
// CHECK-NOT: 3end
// CHECK: getelementptr {{.*}}, i32 0
- // CHECK: getelementptr {{.*}}, i64 5
+ // CHECK: getelementptr {{.*}}, i64 1, i64 0
// CHECK: br label %[[COND:.*]]
// CHECK: [[COND]]:
int (*fp)(int, int) = [](int x, int y){ return x + y; };
}
+static int k;
+int g() {
+ int &r = k;
+ // CHECK: define internal i32 @"_ZZ1gvENK3$_6clEv"(
+ // CHECK-NOT: }
+ // CHECK: load i32* @_ZL1k,
+ return [] { return r; } ();
+};
+
// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
const int h = a; // expected-note {{declared}}
[]() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
- // The exemption for variables which can appear in constant expressions
- // applies only to objects (and not to references).
- // FIXME: This might be a bug in the standard.
- static int i;
- constexpr int &ref_i = i; // expected-note {{declared}}
+ // References can appear in constant expressions if they are initialized by
+ // reference constant expressions.
+ int i;
+ int &ref_i = i; // expected-note {{declared}}
[] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+
+ static int j;
+ int &ref_j = j;
+ [] { return ref_j; }; // ok
}
}