reference binding to an expression.
We need to know the array bound in order to determine whether the
parameter type is reference-compatible with the argument type, so we
need to trigger instantiation in this case.
return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser);
}
+ /// Get the type of expression E, triggering instantiation to complete the
+ /// type if necessary -- that is, if the expression refers to a templated
+ /// static data member of incomplete array type.
+ ///
+ /// May still return an incomplete type if instantiation was not possible or
+ /// if the type is incomplete for a different reason. Use
+ /// RequireCompleteExprType instead if a diagnostic is expected for an
+ /// incomplete expression type.
+ QualType getCompletedType(Expr *E);
+
void completeExprArrayBound(Expr *E);
bool RequireCompleteExprType(Expr *E, CompleteTypeKind Kind,
TypeDiagnoser &Diagnoser);
// bind to that.
if (InitList->getNumInits() == 1) {
Expr *Initializer = InitList->getInit(0);
- QualType cv2T2 = Initializer->getType();
+ QualType cv2T2 = S.getCompletedType(Initializer);
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
- QualType cv2T2 = Initializer->getType();
+ QualType cv2T2 = S.getCompletedType(Initializer);
Qualifiers T2Quals;
QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals);
if (ParamRefType) {
// If the argument has incomplete array type, try to complete its type.
- if (ArgType->isIncompleteArrayType()) {
- S.completeExprArrayBound(Arg);
- ArgType = Arg->getType();
- }
+ if (ArgType->isIncompleteArrayType())
+ ArgType = S.getCompletedType(Arg);
// C++1z [temp.deduct.call]p3:
// If P is a forwarding reference and the argument is an lvalue, the type
}
}
+QualType Sema::getCompletedType(Expr *E) {
+ // Incomplete array types may be completed by the initializer attached to
+ // their definitions. For static data members of class templates and for
+ // variable templates, we need to instantiate the definition to get this
+ // initializer and complete the type.
+ if (E->getType()->isIncompleteArrayType())
+ completeExprArrayBound(E);
+
+ // FIXME: Are there other cases which require instantiating something other
+ // than the type to complete the type of an expression?
+
+ return E->getType();
+}
+
/// Ensure that the type of the given expression is complete.
///
/// This routine checks whether the expression \p E has a complete type. If the
/// otherwise.
bool Sema::RequireCompleteExprType(Expr *E, CompleteTypeKind Kind,
TypeDiagnoser &Diagnoser) {
- QualType T = E->getType();
-
- // Incomplete array types may be completed by the initializer attached to
- // their definitions. For static data members of class templates and for
- // variable templates, we need to instantiate the definition to get this
- // initializer and complete the type.
- if (T->isIncompleteArrayType()) {
- completeExprArrayBound(E);
- T = E->getType();
- }
-
- // FIXME: Are there other cases which require instantiating something other
- // than the type to complete the type of an expression?
-
- return RequireCompleteType(E->getExprLoc(), T, Kind, Diagnoser);
+ return RequireCompleteType(E->getExprLoc(), getCompletedType(E), Kind,
+ Diagnoser);
}
bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) {
void testStaticVarWithTypedefString() {
(void)StaticVarWithTypedefString<int>::str;
}
+
+namespace ArrayBound {
+#if __cplusplus >= 201103L
+ template<typename T> void make_unique(T &&);
+
+ template<typename> struct Foo {
+ static constexpr char kMessage[] = "abc";
+ static void f() { make_unique(kMessage); }
+ static void g1() { const char (&ref)[4] = kMessage; } // OK
+ // We can diagnose this prior to instantiation because kMessage is not type-dependent.
+ static void g2() { const char (&ref)[5] = kMessage; } // expected-error {{could not bind}}
+ };
+ template void Foo<int>::f();
+#endif
+
+ template<typename> struct Bar {
+ static const char kMessage[];
+ // Here, kMessage is type-dependent, so we don't diagnose until
+ // instantiation.
+ static void g1() { const char (&ref)[4] = kMessage; } // expected-error {{could not bind to an lvalue of type 'const char [5]'}}
+ static void g2() { const char (&ref)[5] = kMessage; } // expected-error {{could not bind to an lvalue of type 'const char [4]'}}
+ };
+ template<typename T> const char Bar<T>::kMessage[] = "foo";
+ template void Bar<int>::g1();
+ template void Bar<int>::g2(); // expected-note {{in instantiation of}}
+
+ template<> const char Bar<char>::kMessage[] = "foox";
+ template void Bar<char>::g1(); // expected-note {{in instantiation of}}
+ template void Bar<char>::g2();
+}