/// Look up the std::experimental::coroutine_handle<PromiseType>. static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, SourceLocation Loc) { if (PromiseType.isNull()) return QualType(); NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); assert(StdExp && "Should already be diagnosed"); LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"), Loc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, StdExp)) { S.Diag(Loc, diag::err_implied_coroutine_type_not_found) << "std::experimental::coroutine_handle"; return QualType(); } ClassTemplateDecl *CoroHandle = Result.getAsSingle<ClassTemplateDecl>(); if (!CoroHandle) { Result.suppressDiagnostics(); // We found something weird. Complain about the first thing we found. NamedDecl *Found = *Result.begin(); S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_handle); return QualType(); } // Form template argument list for coroutine_handle<Promise>. TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument(TemplateArgumentLoc( TemplateArgument(PromiseType), S.Context.getTrivialTypeSourceInfo(PromiseType, Loc))); // Build the template-id. QualType CoroHandleType = S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args); if (CoroHandleType.isNull()) return QualType(); if (S.RequireCompleteType(Loc, CoroHandleType, diag::err_coroutine_type_missing_specialization)) return QualType(); return CoroHandleType; }
/// Look up the std::coroutine_traits<...>::promise_type for the given /// function type. static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, SourceLocation KwLoc, SourceLocation FuncLoc) { // FIXME: Cache std::coroutine_traits once we've found it. NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); if (!StdExp) { S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) << "std::experimental::coroutine_traits"; return QualType(); } LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), FuncLoc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, StdExp)) { S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) << "std::experimental::coroutine_traits"; return QualType(); } ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>(); if (!CoroTraits) { Result.suppressDiagnostics(); // We found something weird. Complain about the first thing we found. NamedDecl *Found = *Result.begin(); S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); return QualType(); } // Form template argument list for coroutine_traits<R, P1, P2, ...>. TemplateArgumentListInfo Args(KwLoc, KwLoc); Args.addArgument(TemplateArgumentLoc( TemplateArgument(FnType->getReturnType()), S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc))); // FIXME: If the function is a non-static member function, add the type // of the implicit object parameter before the formal parameters. for (QualType T : FnType->getParamTypes()) Args.addArgument(TemplateArgumentLoc( TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc))); // Build the template-id. QualType CoroTrait = S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args); if (CoroTrait.isNull()) return QualType(); if (S.RequireCompleteType(KwLoc, CoroTrait, diag::err_coroutine_type_missing_specialization)) return QualType(); auto *RD = CoroTrait->getAsCXXRecordDecl(); assert(RD && "specialization of class template is not a class?"); // Look up the ::promise_type member. LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc, Sema::LookupOrdinaryName); S.LookupQualifiedName(R, RD); auto *Promise = R.getAsSingle<TypeDecl>(); if (!Promise) { S.Diag(FuncLoc, diag::err_implied_std_coroutine_traits_promise_type_not_found) << RD; return QualType(); } // The promise type is required to be a class type. QualType PromiseType = S.Context.getTypeDeclType(Promise); auto buildElaboratedType = [&]() { auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); return S.Context.getElaboratedType(ETK_None, NNS, PromiseType); }; if (!PromiseType->getAsCXXRecordDecl()) { S.Diag(FuncLoc, diag::err_implied_std_coroutine_traits_promise_type_not_class) << buildElaboratedType(); return QualType(); } if (S.RequireCompleteType(FuncLoc, buildElaboratedType(), diag::err_coroutine_promise_type_incomplete)) return QualType(); return PromiseType; }
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, // or "pointer to cv void". QualType DestPointee; const PointerType *DestPointer = DestType->getAsPointerType(); const ReferenceType *DestReference = DestType->getAsReferenceType(); if (DestPointer) { DestPointee = DestPointer->getPointeeType(); } else if (DestReference) { DestPointee = DestReference->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) << OrigDestType << DestRange; return; } const RecordType *DestRecord = DestPointee->getAsRecordType(); if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, diag::err_bad_dynamic_cast_incomplete, DestRange)) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << DestPointee.getUnqualifiedType() << DestRange; return; } // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to // complete class type, [...]. If T is an lvalue reference type, v shall be // an lvalue of a complete class type, [...]. If T is an rvalue reference // type, v shall be an expression having a complete effective class type, // [...] QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); QualType SrcPointee; if (DestPointer) { if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { SrcPointee = SrcPointer->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) << OrigSrcType << SrcExpr->getSourceRange(); return; } } else if (DestReference->isLValueReferenceType()) { if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << "dynamic_cast" << OrigDestType << OpRange; } SrcPointee = SrcType; } else { SrcPointee = SrcType; } const RecordType *SrcRecord = SrcPointee->getAsRecordType(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_dynamic_cast_incomplete, SrcExpr->getSourceRange())) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); return; } assert((DestPointer || DestReference) && "Bad destination non-ptr/ref slipped through."); assert((DestRecord || DestPointee->isVoidType()) && "Bad destination pointee slipped through."); assert(SrcRecord && "Bad source pointee slipped through."); // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) << "dynamic_cast" << OrigDestType << OrigSrcType << OpRange; return; } // C++ 5.2.7p3: If the type of v is the same as the required result type, // [except for cv]. if (DestRecord == SrcRecord) { return; } // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, OpRange.getBegin(), OpRange); // Diagnostic already emitted on error. return; } // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); assert(SrcDecl && "Definition missing"); if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); } // Done. Everything else is run-time checks. }