@@ -1839,19 +1839,24 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
18391839 RestrictAttr (S.Context , AL, DeallocE, DeallocPtrIdx));
18401840}
18411841
1842- static bool checkSpanLikeType (Sema &S, const ParsedAttr &AL,
1843- const QualType &Ty) {
1844- // Check that the type is a plain record with one field being a pointer
1845- // type and the other field being an integer. This matches the common
1846- // implementation of std::span or sized_allocation_t in P0901R11.
1842+ bool Sema::CheckSpanLikeType (const AttributeCommonInfo &CI,
1843+ const QualType &Ty) {
18471844 // Note that there may also be numerous cases of pointer + integer /
18481845 // pointer + pointer / integer + pointer structures not actually exhibiting
18491846 // a span-like semantics, so sometimes these heuristics expectedly
18501847 // lead to false positive results.
1851- auto emitWarning = [&S , &AL ](unsigned NoteDiagID) {
1852- S. Diag (AL .getLoc (), diag::warn_attribute_return_span_only) << AL ;
1853- return S. Diag (AL .getLoc (), NoteDiagID);
1848+ auto emitWarning = [this , &CI ](unsigned NoteDiagID) {
1849+ Diag (CI .getLoc (), diag::warn_attribute_return_span_only) << CI ;
1850+ return Diag (CI .getLoc (), NoteDiagID);
18541851 };
1852+ if (!Ty->isDependentType ()) {
1853+ // If the type is a class template specialization, it may not be
1854+ // instantiated at this stage. We must force it to be complete to examine
1855+ // its fields.
1856+ // The returned value is discarded since the code below emits a warning
1857+ // if the type keeps being incomplete.
1858+ (void )isCompleteType (CI.getLoc (), Ty);
1859+ }
18551860 if (Ty->isIncompleteType ())
18561861 return emitWarning (diag::note_returned_incomplete_type);
18571862 const RecordDecl *RD = Ty->getAsRecordDecl ();
@@ -1867,13 +1872,13 @@ static bool checkSpanLikeType(Sema &S, const ParsedAttr &AL,
18671872 // It must not point to functions.
18681873 return T->isPointerType () && !T->isFunctionPointerType ();
18691874 };
1870- auto checkIntegerType = [&S , emitWarning](const QualType &T,
1871- const int FieldNo) -> bool {
1875+ auto checkIntegerType = [this , emitWarning](const QualType &T,
1876+ const int FieldNo) -> bool {
18721877 const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType ());
18731878 if (!BT || !BT->isInteger ())
18741879 return emitWarning (diag::note_returned_not_integer_field) << FieldNo;
1875- const auto IntSize = S. Context .getTypeSize (S. Context .IntTy );
1876- if (S. Context .getTypeSize (BT) < IntSize)
1880+ const auto IntSize = Context.getTypeSize (Context.IntTy );
1881+ if (Context.getTypeSize (BT) < IntSize)
18771882 return emitWarning (diag::note_returned_not_wide_enough_field)
18781883 << FieldNo << IntSize;
18791884 return false ;
@@ -1894,7 +1899,9 @@ static bool checkSpanLikeType(Sema &S, const ParsedAttr &AL,
18941899
18951900static void handleMallocSpanAttr (Sema &S, Decl *D, const ParsedAttr &AL) {
18961901 QualType ResultType = getFunctionOrMethodResultType (D);
1897- if (!checkSpanLikeType (S, AL, ResultType)) {
1902+ if (ResultType->isDependentType () || !S.CheckSpanLikeType (AL, ResultType)) {
1903+ // If it's a dependent type, the attribute will be re-checked upon
1904+ // instantiation.
18981905 D->addAttr (::new (S.Context ) MallocSpanAttr (S.Context , AL));
18991906 }
19001907}
0 commit comments