CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, bool HadMultipleCandidates, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) : Expr(SC, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), Args(0) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; for (unsigned i = 0; i != NumArgs; ++i) { assert(args[i] && "NULL argument in CXXConstructExpr"); if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; if (args[i]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; Args[i] = args[i]; } } }
// CXXNewExpr CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, bool parenTypeId, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, FunctionDecl *operatorDelete, QualType ty, SourceLocation startLoc, SourceLocation endLoc) : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()), GlobalNew(globalNew), ParenTypeId(parenTypeId), Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; SubExprs = new Stmt*[TotalSize]; unsigned i = 0; if (Array) SubExprs[i++] = arraySize; for (unsigned j = 0; j < NumPlacementArgs; ++j) SubExprs[i++] = placementArgs[j]; for (unsigned j = 0; j < NumConstructorArgs; ++j) SubExprs[i++] = constructorArgs[j]; assert(i == TotalSize); }
// CXXNewExpr CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, bool HadMultipleCandidates, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, QualType ty, TypeSourceInfo *AllocatedTypeInfo, SourceLocation startLoc, SourceLocation endLoc, SourceLocation constructorLParen, SourceLocation constructorRParen) : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->isInstantiationDependentType(), ty->containsUnexpandedParameterPack()), GlobalNew(globalNew), Initializer(initializer), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), HadMultipleCandidates(HadMultipleCandidates), SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens), StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen), ConstructorRParen(constructorRParen) { AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs); unsigned i = 0; if (Array) { if (arraySize->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (arraySize->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; SubExprs[i++] = arraySize; } for (unsigned j = 0; j < NumPlacementArgs; ++j) { if (placementArgs[j]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (placementArgs[j]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; SubExprs[i++] = placementArgs[j]; } for (unsigned j = 0; j < NumConstructorArgs; ++j) { if (constructorArgs[j]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (constructorArgs[j]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; SubExprs[i++] = constructorArgs[j]; } }
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) { if (NumArgs > 0) { Args = new (C) Stmt*[NumArgs]; for (unsigned i = 0; i < NumArgs; ++i) Args[i] = args[i]; } }
long long clang_Type_getSizeOf(CXType T) { if (T.kind == CXType_Invalid) return CXTypeLayoutError_Invalid; ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); QualType QT = GetQualType(T); // [expr.sizeof] p2: if reference type, return size of referenced type if (QT->isReferenceType()) QT = QT.getNonReferenceType(); // [expr.sizeof] p1: return -1 on: func, incomplete, bitfield, incomplete // enumeration // Note: We get the cxtype, not the cxcursor, so we can't call // FieldDecl->isBitField() // [expr.sizeof] p3: pointer ok, function not ok. // [gcc extension] lib/AST/ExprConstant.cpp:1372 HandleSizeof : vla == error if (QT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (QT->isDependentType()) return CXTypeLayoutError_Dependent; if (!QT->isConstantSizeType()) return CXTypeLayoutError_NotConstantSize; // [gcc extension] lib/AST/ExprConstant.cpp:1372 // HandleSizeof : {voidtype,functype} == 1 // not handled by ASTContext.cpp:1313 getTypeInfoImpl if (QT->isVoidType() || QT->isFunctionType()) return 1; return Ctx.getTypeSizeInChars(QT).getQuantity(); }
/// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 0 << D.getSourceRange(); else if (AllocType->isReferenceType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 1 << D.getSourceRange(); else if (!AllocType->isDependentType() && RequireCompleteType(D.getSourceRange().getBegin(), AllocType, diag::err_new_incomplete_type, D.getSourceRange())) return true; else if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, diag::err_allocation_of_abstract_type)) return true; // Every dimension shall be of constant size. unsigned i = 1; while (const ArrayType *Array = Context.getAsArrayType(AllocType)) { if (!Array->isConstantArrayType()) { Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); return true; } AllocType = Array->getElementType(); ++i; } return false; }
static long long validateFieldParentType(CXCursor PC, CXType PT){ if (clang_isInvalid(PC.kind)) return CXTypeLayoutError_Invalid; const RecordDecl *RD = dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); // validate parent declaration if (!RD || RD->isInvalidDecl()) return CXTypeLayoutError_Invalid; RD = RD->getDefinition(); if (!RD) return CXTypeLayoutError_Incomplete; if (RD->isInvalidDecl()) return CXTypeLayoutError_Invalid; // validate parent type QualType RT = GetQualType(PT); if (RT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (RT->isDependentType()) return CXTypeLayoutError_Dependent; // We recurse into all record fields to detect incomplete and dependent types. long long Error = visitRecordForValidation(RD); if (Error < 0) return Error; return 0; }
/// \brief Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { if (!SD) return false; // Namespace and namespace aliases are fine. if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD)) return true; if (!isa<TypeDecl>(SD)) return false; // Determine whether we have a class (or, in C++11, an enum) or // a typedef thereof. If so, build the nested-name-specifier. QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); if (T->isDependentType()) return true; else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { if (TD->getUnderlyingType()->isRecordType() || (Context.getLangOptions().CPlusPlus0x && TD->getUnderlyingType()->isEnumeralType())) return true; } else if (isa<RecordDecl>(SD) || (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD))) return true; return false; }
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc) { if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error) return true; assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); if (T.isNull()) return true; if (!T->isDependentType() && !T->getAs<TagType>()) { Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace) << T << getLangOpts().CPlusPlus; return true; } TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), ColonColonLoc); return false; }
QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) return FD->getResultType(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getResultType(); if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { // Blocks are difficult because the return type may not be stored in the // BlockDecl itself. The AST should probably be enhanced, but for now we // just do what we can. // If the block is declared without an explicit argument list, the // signature-as-written just includes the return type, not the entire // function type. // FIXME: All blocks should have signatures-as-written, even if the return // type is inferred. (That's signified with a dependent result type.) if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) { QualType Ty = TSI->getType(); if (const FunctionType *FT = Ty->getAs<FunctionType>()) Ty = FT->getResultType(); if (!Ty->isDependentType()) return Ty; } return QualType(); } llvm_unreachable("unknown callable kind"); }
UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo, TemplateArgs, Begin, End, // Dependent ((Base && Base->isTypeDependent()) || BaseType->isDependentType()), ((Base && Base->isInstantiationDependent()) || BaseType->isInstantiationDependentType()), // Contains unexpanded parameter pack ((Base && Base->containsUnexpandedParameterPack()) || BaseType->containsUnexpandedParameterPack())), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { // Check whether all of the members are non-static member functions, // and if so, mark give this bound-member type instead of overload type. if (hasOnlyNonStaticMemberFunctions(Begin, End)) setType(C.BoundMemberTy); }
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) { Info.clear(); if (IsUnevaluatedContext) PushExpressionEvaluationContext(UnevaluatedAbstract, ReuseLambdaContextDecl); ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, /*trailing lparen*/ false, /*is & operand*/ false, /*CorrectionCandidateCallback=*/nullptr, /*IsInlineAsmIdentifier=*/ true); if (IsUnevaluatedContext) PopExpressionEvaluationContext(); if (!Result.isUsable()) return Result; Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; QualType T = Result.get()->getType(); // For now, reject dependent types. if (T->isDependentType()) { Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; return ExprError(); } // Any sort of function type is fine. if (T->isFunctionType()) { return Result; } // Otherwise, it needs to be a complete type. if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { return ExprError(); } // Compute the type size (and array length if applicable?). Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); if (T->isArrayType()) { const ArrayType *ATy = Context.getAsArrayType(T); Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); Info.Length = Info.Size / Info.Type; } // We can work with the expression as long as it's not an r-value. if (!Result.get()->isRValue()) Info.IsVarDecl = true; return Result; }
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) { Info.clear(); if (IsUnevaluatedContext) PushExpressionEvaluationContext(UnevaluatedAbstract, ReuseLambdaContextDecl); ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, /*trailing lparen*/ false, /*is & operand*/ false, /*CorrectionCandidateCallback=*/nullptr, /*IsInlineAsmIdentifier=*/ true); if (IsUnevaluatedContext) PopExpressionEvaluationContext(); if (!Result.isUsable()) return Result; Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(Result.get(), *this)) return ExprError(); QualType T = Result.get()->getType(); // For now, reject dependent types. if (T->isDependentType()) { Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; return ExprError(); } // Any sort of function type is fine. if (T->isFunctionType()) { return Result; } // Otherwise, it needs to be a complete type. if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { return ExprError(); } fillInlineAsmTypeInfo(Context, T, Info); // We can work with the expression as long as it's not an r-value. if (!Result.get()->isRValue()) Info.IsVarDecl = true; return Result; }
ExprResult Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc) { Info.clear(); QualType T = E->getType(); if (T->isDependentType()) { DeclarationNameInfo NameInfo; NameInfo.setLoc(AsmLoc); NameInfo.setName(&Context.Idents.get(Member)); return CXXDependentScopeMemberExpr::Create( Context, E, T, /*IsArrow=*/false, AsmLoc, NestedNameSpecifierLoc(), SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr); } const RecordType *RT = T->getAs<RecordType>(); // FIXME: Diagnose this as field access into a scalar type. if (!RT) return ExprResult(); LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc, LookupMemberName); if (!LookupQualifiedName(FieldResult, RT->getDecl())) return ExprResult(); // Only normal and indirect field results will work. ValueDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl()); if (!FD) FD = dyn_cast<IndirectFieldDecl>(FieldResult.getFoundDecl()); if (!FD) return ExprResult(); // Make an Expr to thread through OpDecl. ExprResult Result = BuildMemberReferenceExpr( E, E->getType(), AsmLoc, /*IsArrow=*/false, CXXScopeSpec(), SourceLocation(), nullptr, FieldResult, nullptr, nullptr); if (Result.isInvalid()) return Result; Info.OpDecl = Result.get(); fillInlineAsmTypeInfo(Context, Result.get()->getType(), Info); // Fields are "variables" as far as inline assembly is concerned. Info.IsVarDecl = true; return Result; }
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. Action::OwningExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, TypeTy *Ty, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, ExprArg E, SourceLocation RParenLoc) { Expr *Ex = E.takeAs<Expr>(); // FIXME: Preserve type source info. QualType DestType = GetTypeFromParser(Ty); SourceRange OpRange(OpLoc, RParenLoc); SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); switch (Kind) { default: assert(0 && "Unknown C++ cast!"); case tok::kw_const_cast: if (!TypeDependent) CheckConstCast(*this, Ex, DestType, OpRange, DestRange); return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), Ex, DestType, OpLoc)); case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (!TypeDependent) CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), Kind, Ex, DestType, OpLoc)); } case tok::kw_reinterpret_cast: if (!TypeDependent) CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), Ex, DestType, OpLoc)); case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (!TypeDependent) CheckStaticCast(*this, Ex, DestType, OpRange, Kind); return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), Kind, Ex, DestType, OpLoc)); } } return ExprError(); }
// CLIGCNewExpr CLIGCNewExpr::CLIGCNewExpr(ASTContext &C, CXXNewExpr::InitializationStyle initializationStyle, Expr *initializer, QualType ty, TypeSourceInfo *allocatedTypeInfo, SourceLocation startLoc, SourceRange directInitRange) : Expr(CLIGCNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->isInstantiationDependentType(), ty->containsUnexpandedParameterPack()), Initializer(0), AllocatedTypeInfo(allocatedTypeInfo), StartLoc(startLoc), DirectInitRange(directInitRange) { assert((initializer != 0 || initializationStyle == CXXNewExpr::NoInit) && "Only NoInit can have no initializer."); StoredInitializationStyle = initializer ? initializationStyle + 1 : 0; if (initializer) { //if (initializer->isInstantiationDependent()) // ExprBits.InstantiationDependent = true; //if (initializer->containsUnexpandedParameterPack()) // ExprBits.ContainsUnexpandedParameterPack = true; Initializer = initializer; } }
bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, ParsedType ObjectTypePtr) { QualType ObjectType = GetTypeFromParser(ObjectTypePtr); LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, false); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); } if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. // The declaration context must be complete. if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS, LookupCtx)) return false; LookupQualifiedName(Found, LookupCtx); } else if (isDependent) { return false; } else { LookupName(Found, S); } Found.suppressDiagnostics(); if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); return false; }
CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( SourceLocation TyBeginLoc, QualType T, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(), T->isDependentType(), true), TyBeginLoc(TyBeginLoc), Type(T), LParenLoc(LParenLoc), RParenLoc(RParenLoc), NumArgs(NumArgs) { Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs); }
// CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { if (ICE->getCastKind() != CK_UserDefinedConversion && ICE->getType()->isVoidPointerType()) Arg = ICE->getSubExpr(); else break; } // The type-to-delete may not be a pointer if it's a dependent type. const QualType ArgType = Arg->getType(); if (ArgType->isDependentType() && !ArgType->isPointerType()) return QualType(); return ArgType->getAs<PointerType>()->getPointeeType(); }
// Based on QualType::isTrivial. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (Type.isNull()) return false; if (Type->isArrayType()) return isTriviallyDefaultConstructible(Context.getBaseElementType(Type), Context); // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (Type->isIncompleteType()) return false; if (Context.getLangOpts().ObjCAutoRefCount) { switch (Type.getObjCLifetime()) { case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; case Qualifiers::OCL_None: if (Type->isObjCLifetimeType()) return false; break; } } QualType CanonicalType = Type.getCanonicalType(); if (CanonicalType->isDependentType()) return false; // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); } // No other types can match. return false; }
bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, CastExpr::CastKind &Kind, bool FunctionalStyle) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) return false; // If the type is dependent, we won't do any other semantic analysis now. if (CastTy->isDependentType() || CastExpr->isTypeDependent()) return false; if (!CastTy->isLValueReferenceType()) DefaultFunctionArrayConversion(CastExpr); // C++ [expr.cast]p5: The conversions performed by // - a const_cast, // - a static_cast, // - a static_cast followed by a const_cast, // - a reinterpret_cast, or // - a reinterpret_cast followed by a const_cast, // can be performed using the cast notation of explicit type conversion. // [...] If a conversion can be interpreted in more than one of the ways // listed above, the interpretation that appears first in the list is used, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true,msg); if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, Kind, msg); if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg); } } if (tcr != TC_Success && msg != 0) Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) << CastExpr->getType() << CastTy << R; return tcr != TC_Success; }
long long clang_Type_getOffsetOf(CXType PT, const char *S) { // check that PT is not incomplete/dependent CXCursor PC = clang_getTypeDeclaration(PT); if (clang_isInvalid(PC.kind)) return CXTypeLayoutError_Invalid; const RecordDecl *RD = dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); if (!RD || RD->isInvalidDecl()) return CXTypeLayoutError_Invalid; RD = RD->getDefinition(); if (!RD) return CXTypeLayoutError_Incomplete; if (RD->isInvalidDecl()) return CXTypeLayoutError_Invalid; QualType RT = GetQualType(PT); if (RT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (RT->isDependentType()) return CXTypeLayoutError_Dependent; // We recurse into all record fields to detect incomplete and dependent types. long long Error = visitRecordForValidation(RD); if (Error < 0) return Error; if (!S) return CXTypeLayoutError_InvalidFieldName; // lookup field ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext(); IdentifierInfo *II = &Ctx.Idents.get(S); DeclarationName FieldName(II); RecordDecl::lookup_const_result Res = RD->lookup(FieldName); // If a field of the parent record is incomplete, lookup will fail. // and we would return InvalidFieldName instead of Incomplete. // But this erroneous results does protects again a hidden assertion failure // in the RecordLayoutBuilder if (Res.size() != 1) return CXTypeLayoutError_InvalidFieldName; if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front())) return Ctx.getFieldOffset(FD); if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(Res.front())) return Ctx.getFieldOffset(IFD); // we don't want any other Decl Type. return CXTypeLayoutError_InvalidFieldName; }
long long clang_Type_getAlignOf(CXType T) { if (T.kind == CXType_Invalid) return CXTypeLayoutError_Invalid; ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); QualType QT = GetQualType(T); // [expr.alignof] p1: return size_t value for complete object type, reference // or array. // [expr.alignof] p3: if reference type, return size of referenced type if (QT->isReferenceType()) QT = QT.getNonReferenceType(); if (QT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (QT->isDependentType()) return CXTypeLayoutError_Dependent; // Exceptions by GCC extension - see ASTContext.cpp:1313 getTypeInfoImpl // if (QT->isFunctionType()) return 4; // Bug #15511 - should be 1 // if (QT->isVoidType()) return 1; return Ctx.getTypeAlignInChars(QT).getQuantity(); }
static long long visitRecordForValidation(const RecordDecl *RD) { for (const auto *I : RD->fields()){ QualType FQT = I->getType(); if (FQT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (FQT->isDependentType()) return CXTypeLayoutError_Dependent; // recurse if (const RecordType *ChildType = I->getType()->getAs<RecordType>()) { if (const RecordDecl *Child = ChildType->getDecl()) { long long ret = visitRecordForValidation(Child); if (ret < 0) return ret; } } // else try next field } return 0; }
static long long visitRecordForValidation(const RecordDecl *RD) { for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I){ QualType FQT = (*I)->getType(); if (FQT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (FQT->isDependentType()) return CXTypeLayoutError_Dependent; // recurse if (const RecordType *ChildType = (*I)->getType()->getAs<RecordType>()) { if (const RecordDecl *Child = ChildType->getDecl()) { long long ret = visitRecordForValidation(Child); if (ret < 0) return ret; } } // else try next field } return 0; }
/// Checks whether one class is derived from another, inclusively. /// Properly indicates when it couldn't be determined due to /// dependence. /// /// This should probably be donated to AST or at least Sema. static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, const CXXRecordDecl *Target) { assert(Derived->getCanonicalDecl() == Derived); assert(Target->getCanonicalDecl() == Target); if (Derived == Target) return AR_accessible; AccessResult OnFailure = AR_inaccessible; llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack while (true) { for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { const CXXRecordDecl *RD; QualType T = I->getType(); if (const RecordType *RT = T->getAs<RecordType>()) { RD = cast<CXXRecordDecl>(RT->getDecl()); } else { // It's possible for a base class to be the current // instantiation of some enclosing template, but I'm guessing // nobody will ever care that we just dependently delay here. assert(T->isDependentType() && "non-dependent base wasn't a record?"); OnFailure = AR_dependent; continue; } RD = RD->getCanonicalDecl(); if (RD == Target) return AR_accessible; Queue.push_back(RD); } if (Queue.empty()) break; Derived = Queue.back(); Queue.pop_back(); } return OnFailure; }
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, ExprArg Operand) { // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type // having a single conversion function to a pointer type. The result has // type void." // DR599 amends "pointer type" to "pointer to object type" in both cases. Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (Type->isRecordType()) { // FIXME: Find that one conversion function and amend the type. } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); QualType Pointee = Type->getAsPointerType()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex->getSourceRange())) return ExprError(); // FIXME: Look up the correct operator delete overload and pass a pointer // along. // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0, Ex, StartLoc)); }
/// Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. /// \param SD Declaration checked for nested-name-specifier. /// \param IsExtension If not null and the declaration is accepted as an /// extension, the pointed variable is assigned true. bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD, bool *IsExtension) { if (!SD) return false; SD = SD->getUnderlyingDecl(); // Namespace and namespace aliases are fine. if (isa<NamespaceDecl>(SD)) return true; if (!isa<TypeDecl>(SD)) return false; // Determine whether we have a class (or, in C++11, an enum) or // a typedef thereof. If so, build the nested-name-specifier. QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); if (T->isDependentType()) return true; if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { if (TD->getUnderlyingType()->isRecordType()) return true; if (TD->getUnderlyingType()->isEnumeralType()) { if (Context.getLangOpts().CPlusPlus11) return true; if (IsExtension) *IsExtension = true; } } else if (isa<RecordDecl>(SD)) { return true; } else if (isa<EnumDecl>(SD)) { if (Context.getLangOpts().CPlusPlus11) return true; if (IsExtension) *IsExtension = true; } return false; }
Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc) { QualType EncodedType = EncodedTypeInfo->getType(); QualType StrTy; if (EncodedType->isDependentType()) StrTy = Context.DependentTy; else { std::string Str; Context.getObjCEncodingForType(EncodedType, Str); // The type of @encode is the same as the type of the corresponding string, // which is an array type. StrTy = Context.CharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) StrTy.addConst(); StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), ArrayType::Normal, 0); } return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc); }
bool CXXBasePaths::lookupInBases(ASTContext &Context, const CXXRecordDecl *Record, CXXRecordDecl::BaseMatchesCallback *BaseMatches, void *UserData) { bool FoundPath = false; // The access of the path down to this record. AccessSpecifier AccessToHere = ScratchPath.Access; bool IsFirstStep = ScratchPath.empty(); for (CXXRecordDecl::base_class_const_iterator BaseSpec = Record->bases_begin(), BaseSpecEnd = Record->bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { // Find the record of the base class subobjects for this type. QualType BaseType = Context.getCanonicalType(BaseSpec->getType()) .getUnqualifiedType(); // C++ [temp.dep]p3: // In the definition of a class template or a member of a class template, // if a base class of the class template depends on a template-parameter, // the base class scope is not examined during unqualified name lookup // either at the point of definition of the class template or member or // during an instantiation of the class tem- plate or member. if (BaseType->isDependentType()) continue; // Determine whether we need to visit this base class at all, // updating the count of subobjects appropriately. std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; bool VisitBase = true; bool SetVirtual = false; if (BaseSpec->isVirtual()) { VisitBase = !Subobjects.first; Subobjects.first = true; if (isDetectingVirtual() && DetectedVirtual == 0) { // If this is the first virtual we find, remember it. If it turns out // there is no base path here, we'll reset it later. DetectedVirtual = BaseType->getAs<RecordType>(); SetVirtual = true; } } else ++Subobjects.second; if (isRecordingPaths()) { // Add this base specifier to the current path. CXXBasePathElement Element; Element.Base = &*BaseSpec; Element.Class = Record; if (BaseSpec->isVirtual()) Element.SubobjectNumber = 0; else Element.SubobjectNumber = Subobjects.second; ScratchPath.push_back(Element); // Calculate the "top-down" access to this base class. // The spec actually describes this bottom-up, but top-down is // equivalent because the definition works out as follows: // 1. Write down the access along each step in the inheritance // chain, followed by the access of the decl itself. // For example, in // class A { public: int foo; }; // class B : protected A {}; // class C : public B {}; // class D : private C {}; // we would write: // private public protected public // 2. If 'private' appears anywhere except far-left, access is denied. // 3. Otherwise, overall access is determined by the most restrictive // access in the sequence. if (IsFirstStep) ScratchPath.Access = BaseSpec->getAccessSpecifier(); else ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } // Track whether there's a path involving this specific base. bool FoundPathThroughBase = false; if (BaseMatches(BaseSpec, ScratchPath, UserData)) { // We've found a path that terminates at this base. FoundPath = FoundPathThroughBase = true; if (isRecordingPaths()) { // We have a path. Make a copy of it before moving on. Paths.push_back(ScratchPath); } else if (!isFindingAmbiguities()) { // We found a path and we don't care about ambiguities; // return immediately. return FoundPath; } } else if (VisitBase) { CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>() ->getDecl()); if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) { // C++ [class.member.lookup]p2: // A member name f in one sub-object B hides a member name f in // a sub-object A if A is a base class sub-object of B. Any // declarations that are so hidden are eliminated from // consideration. // There is a path to a base class that meets the criteria. If we're // not collecting paths or finding ambiguities, we're done. FoundPath = FoundPathThroughBase = true; if (!isFindingAmbiguities()) return FoundPath; } } // Pop this base specifier off the current path (if we're // collecting paths). if (isRecordingPaths()) { ScratchPath.pop_back(); } // If we set a virtual earlier, and this isn't a path, forget it again. if (SetVirtual && !FoundPathThroughBase) { DetectedVirtual = 0; } } // Reset the scratch path access. ScratchPath.Access = AccessToHere; return FoundPath; }