================
@@ -7357,11 +7357,12 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
E->getStorageDuration() == SD_Thread) && "not a global temporary");
const auto *VD = cast<VarDecl>(E->getExtendingDecl());
- // If we're not materializing a subobject of the temporary, keep the
- // cv-qualifiers from the type of the MaterializeTemporaryExpr.
- QualType MaterializedType = Init->getType();
- if (Init == E->getSubExpr())
- MaterializedType = E->getType();
+ // Keep cv-qualifiers from the MaterializeTemporaryExpr on the storage type.
+ // The initializer expression may have had rvalue subobject adjustments
+ // stripped, which can drop top-level qualifiers that are still part of the
+ // materialized temporary's type.
+ QualType MaterializedType = getContext().getQualifiedType(
----------------
efriedma-quic wrote:
Looked at this more, I think I understand what's going in here.
skipRValueSubobjectAdjustments() is part of C++98 support: C++98 has a weird
rule that means a class value is technically an rvalue where it really
shouldn't be. (See Sema::TemporaryMaterializationConversion.) Outside of
C++98, the expressions that skipRValueSubobjectAdjustments() can look through
are guaranteed to be xvalues, and we don't materialize values that are already
lvalues. It's just making things more confusing to understand by looking
though CK_NoOp casts.
Outside of the weird C++98 cases, the correct type is exactly the type of the
MaterializeTemporaryExpr: it should have both the correct base type, and the
correct qualifiers. At the point we're materializing, we know whether it
should be a const temporary.
C++98 gets weird, though. Consider:
```
struct S { int x, y; };
const int &xx = S().x;
```
According to C++11 rules, the underlying value is not const: there is no const
at the point where we construct the temporary, so it never gets inherited; you
can cast away the const-ness if you want. And in C++11 codegen, the
MaterializeTemporaryExpr is not const-qualified. However, in C++98, the
MaterializeTemporaryExpr is `const int&`. which is where things get weird. I
think we don't want the temporary to be "const".
Given that context, I think the best way to write this check is:
```
QualType MaterializedType = Init->getType();
if (getContext().hasSameUnqualifiedType(E->getType(), MaterializedType))
MaterializedType = E->getType();
```
That should catch all the cases we care about without affecting the C++98 edge
cases.
https://github.com/llvm/llvm-project/pull/186594
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits