diff options
Diffstat (limited to 'lib/AST')
74 files changed, 9362 insertions, 4581 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index c05b160b8e3d9..1993bba9bd1a1 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -1,9 +1,8 @@ //===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -21,6 +20,61 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// The identity of a type_info object depends on the canonical unqualified +/// type only. +TypeInfoLValue::TypeInfoLValue(const Type *T) + : T(T->getCanonicalTypeUnqualified().getTypePtr()) {} + +void TypeInfoLValue::print(llvm::raw_ostream &Out, + const PrintingPolicy &Policy) const { + Out << "typeid("; + QualType(getType(), 0).print(Out, Policy); + Out << ")"; +} + +static_assert( + 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <= + alignof(Type), + "Type is insufficiently aligned"); + +APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} +APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} + +APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV, + QualType TypeInfo) { + LValueBase Base; + Base.Ptr = LV; + Base.TypeInfoType = TypeInfo.getAsOpaquePtr(); + return Base; +} + +unsigned APValue::LValueBase::getCallIndex() const { + return is<TypeInfoLValue>() ? 0 : Local.CallIndex; +} + +unsigned APValue::LValueBase::getVersion() const { + return is<TypeInfoLValue>() ? 0 : Local.Version; +} + +QualType APValue::LValueBase::getTypeInfoType() const { + assert(is<TypeInfoLValue>() && "not a type_info lvalue"); + return QualType::getFromOpaquePtr(TypeInfoType); +} + +namespace clang { +bool operator==(const APValue::LValueBase &LHS, + const APValue::LValueBase &RHS) { + if (LHS.Ptr != RHS.Ptr) + return false; + if (LHS.is<TypeInfoLValue>()) + return true; + return LHS.Local.CallIndex == RHS.Local.CallIndex && + LHS.Local.Version == RHS.Local.Version; +} +} + namespace { struct LVBase { APValue::LValueBase Base; @@ -46,26 +100,27 @@ APValue::LValueBase::operator bool () const { clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey()); + DenseMapInfo<const ValueDecl*>::getEmptyKey()); } clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey()); + DenseMapInfo<const ValueDecl*>::getTombstoneKey()); +} + +namespace clang { +llvm::hash_code hash_value(const APValue::LValueBase &Base) { + if (Base.is<TypeInfoLValue>()) + return llvm::hash_value(Base.getOpaqueValue()); + return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), + Base.getVersion()); +} } unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue( const clang::APValue::LValueBase &Base) { - llvm::FoldingSetNodeID ID; - ID.AddPointer(Base.getOpaqueValue()); - ID.AddInteger(Base.getCallIndex()); - ID.AddInteger(Base.getVersion()); - return ID.ComputeHash(); + return hash_value(Base); } bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual( @@ -164,9 +219,11 @@ APValue::UnionData::~UnionData () { delete Value; } -APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { +APValue::APValue(const APValue &RHS) : Kind(None) { switch (RHS.getKind()) { - case Uninitialized: + case None: + case Indeterminate: + Kind = RHS.getKind(); break; case Int: MakeInt(); @@ -176,6 +233,11 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { MakeFloat(); setFloat(RHS.getFloat()); break; + case FixedPoint: { + APFixedPoint FXCopy = RHS.getFixedPoint(); + MakeFixedPoint(std::move(FXCopy)); + break; + } case Vector: MakeVector(); setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts, @@ -233,6 +295,8 @@ void APValue::DestroyDataAndMakeUninit() { ((APSInt*)(char*)Data.buffer)->~APSInt(); else if (Kind == Float) ((APFloat*)(char*)Data.buffer)->~APFloat(); + else if (Kind == FixedPoint) + ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint(); else if (Kind == Vector) ((Vec*)(char*)Data.buffer)->~Vec(); else if (Kind == ComplexInt) @@ -251,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() { ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData(); else if (Kind == AddrLabelDiff) ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData(); - Kind = Uninitialized; + Kind = None; } bool APValue::needsCleanup() const { switch (getKind()) { - case Uninitialized: + case None: + case Indeterminate: case AddrLabelDiff: return false; case Struct: @@ -268,6 +333,8 @@ bool APValue::needsCleanup() const { return getInt().needsCleanup(); case Float: return getFloat().needsCleanup(); + case FixedPoint: + return getFixedPoint().getValue().needsCleanup(); case ComplexFloat: assert(getComplexFloatImag().needsCleanup() == getComplexFloatReal().needsCleanup() && @@ -312,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) { void APValue::dump(raw_ostream &OS) const { switch (getKind()) { - case Uninitialized: - OS << "Uninitialized"; + case None: + OS << "None"; + return; + case Indeterminate: + OS << "Indeterminate"; return; case Int: OS << "Int: " << getInt(); @@ -321,6 +391,9 @@ void APValue::dump(raw_ostream &OS) const { case Float: OS << "Float: " << GetApproxValue(getFloat()); return; + case FixedPoint: + OS << "FixedPoint : " << getFixedPoint(); + return; case Vector: OS << "Vector: "; getVectorElt(0).dump(OS); @@ -383,9 +456,13 @@ void APValue::dump(raw_ostream &OS) const { llvm_unreachable("Unknown APValue kind!"); } -void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ +void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, + QualType Ty) const { switch (getKind()) { - case APValue::Uninitialized: + case APValue::None: + Out << "<out of lifetime>"; + return; + case APValue::Indeterminate: Out << "<uninitialized>"; return; case APValue::Int: @@ -397,6 +474,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ case APValue::Float: Out << GetApproxValue(getFloat()); return; + case APValue::FixedPoint: + Out << getFixedPoint(); + return; case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); @@ -453,7 +533,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; - else { + else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { + TI.print(Out, Ctx.getPrintingPolicy()); + } else { assert(Base.get<const Expr *>() != nullptr && "Expecting non-null Expr"); Base.get<const Expr*>()->printPretty(Out, nullptr, @@ -478,6 +560,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { Out << *VD; ElemTy = VD->getType(); + } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { + TI.print(Out, Ctx.getPrintingPolicy()); + ElemTy = Base.getTypeInfoType(); } else { const Expr *E = Base.get<const Expr*>(); assert(E != nullptr && "Expecting non-null Expr"); @@ -491,8 +576,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (ElemTy->getAs<RecordType>()) { // The lvalue refers to a class type, so the next path entry is a base // or member. - const Decl *BaseOrMember = - BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer(); + const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { CastToBase = RD; ElemTy = Ctx.getRecordType(RD); @@ -506,7 +590,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ } } else { // The lvalue must refer to an array. - Out << '[' << Path[I].ArrayIndex << ']'; + Out << '[' << Path[I].getAsArrayIndex() << ']'; ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); } } @@ -592,7 +676,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ llvm_unreachable("Unknown APValue kind!"); } -std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { +std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const { std::string Result; llvm::raw_string_ostream Out(Result); printPretty(Out, Ctx, Ty); @@ -600,6 +684,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { return Result; } +bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy, + const ASTContext &Ctx) const { + if (isInt()) { + Result = getInt(); + return true; + } + + if (isLValue() && isNullPointer()) { + Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy); + return true; + } + + if (isLValue() && !getLValueBase()) { + Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy); + return true; + } + + return false; +} + const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); return ((const LV*)(const void*)Data.buffer)->Base; @@ -687,21 +791,21 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const { } void APValue::MakeLValue() { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); static_assert(sizeof(LV) <= DataSize, "LV too big"); new ((void*)(char*)Data.buffer) LV(); Kind = LValue; } void APValue::MakeArray(unsigned InitElts, unsigned Size) { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); new ((void*)(char*)Data.buffer) Arr(InitElts, Size); Kind = Array; } void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) { - assert(isUninit() && "Bad state change"); + assert(isAbsent() && "Bad state change"); MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; Kind = MemberPointer; MPD->MemberAndIsDerivedMember.setPointer(Member); diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index 55033b238c660..6bba8f1f80a93 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -1,9 +1,8 @@ //===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 21b6f36e9aa77..0d69eb90abaf6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1,9 +1,8 @@ //===- ASTContext.cpp - Context to hold long-lived AST nodes --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -95,38 +94,18 @@ using namespace clang; -unsigned ASTContext::NumImplicitDefaultConstructors; -unsigned ASTContext::NumImplicitDefaultConstructorsDeclared; -unsigned ASTContext::NumImplicitCopyConstructors; -unsigned ASTContext::NumImplicitCopyConstructorsDeclared; -unsigned ASTContext::NumImplicitMoveConstructors; -unsigned ASTContext::NumImplicitMoveConstructorsDeclared; -unsigned ASTContext::NumImplicitCopyAssignmentOperators; -unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; -unsigned ASTContext::NumImplicitMoveAssignmentOperators; -unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; -unsigned ASTContext::NumImplicitDestructors; -unsigned ASTContext::NumImplicitDestructorsDeclared; - enum FloatingRank { Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { - if (!CommentsLoaded && ExternalSource) { - ExternalSource->ReadComments(); - -#ifndef NDEBUG - ArrayRef<RawComment *> RawComments = Comments.getComments(); - assert(std::is_sorted(RawComments.begin(), RawComments.end(), - BeforeThanCompare<RawComment>(SourceMgr))); -#endif - - CommentsLoaded = true; - } - assert(D); + // If we already tried to load comments but there are none, + // we won't find anything. + if (CommentsLoaded && Comments.getComments().empty()) + return nullptr; + // User can not attach documentation to implicit declarations. if (D->isImplicit()) return nullptr; @@ -176,12 +155,6 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { isa<TemplateTemplateParmDecl>(D)) return nullptr; - ArrayRef<RawComment *> RawComments = Comments.getComments(); - - // If there are no comments anywhere, we won't find anything. - if (RawComments.empty()) - return nullptr; - // Find declaration location. // For Objective-C declarations we generally don't expect to have multiple // declarators, thus use declaration starting location as the "declaration @@ -220,6 +193,23 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (DeclLoc.isInvalid() || !DeclLoc.isFileID()) return nullptr; + if (!CommentsLoaded && ExternalSource) { + ExternalSource->ReadComments(); + +#ifndef NDEBUG + ArrayRef<RawComment *> RawComments = Comments.getComments(); + assert(std::is_sorted(RawComments.begin(), RawComments.end(), + BeforeThanCompare<RawComment>(SourceMgr))); +#endif + + CommentsLoaded = true; + } + + ArrayRef<RawComment *> RawComments = Comments.getComments(); + // If there are no comments anywhere, we won't find anything. + if (RawComments.empty()) + return nullptr; + // Find the comment that occurs just after this declaration. ArrayRef<RawComment *>::iterator Comment; { @@ -238,12 +228,11 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Found) { Comment = MaybeBeforeDecl + 1; - assert(Comment == std::lower_bound(RawComments.begin(), RawComments.end(), - &CommentAtDeclLoc, Compare)); + assert(Comment == + llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare)); } else { // Slow path. - Comment = std::lower_bound(RawComments.begin(), RawComments.end(), - &CommentAtDeclLoc, Compare); + Comment = llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare); } } @@ -265,6 +254,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) == SourceMgr.getLineNumber(CommentBeginDecomp.first, CommentBeginDecomp.second)) { + (**Comment).setAttached(); return *Comment; } } @@ -306,6 +296,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (Text.find_first_of(";{}#@") != StringRef::npos) return nullptr; + (**Comment).setAttached(); return *Comment; } @@ -835,6 +826,9 @@ ASTContext::~ASTContext() { for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); + + for (APValue *Value : APValueCleanups) + Value->~APValue(); } class ASTContext::ParentMap { @@ -913,7 +907,7 @@ void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) { Parents.reset(); } -void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { +void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const { Deallocations.push_back({Callback, Data}); } @@ -1391,24 +1385,6 @@ ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, TemplateOrInstantiation[Inst] = TSI; } -FunctionDecl *ASTContext::getClassScopeSpecializationPattern( - const FunctionDecl *FD){ - assert(FD && "Specialization is 0"); - llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos - = ClassScopeSpecializationPattern.find(FD); - if (Pos == ClassScopeSpecializationPattern.end()) - return nullptr; - - return Pos->second; -} - -void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD, - FunctionDecl *Pattern) { - assert(FD && "Specialization is 0"); - assert(Pattern && "Class scope specialization pattern is 0"); - ClassScopeSpecializationPattern[FD] = Pattern; -} - NamedDecl * ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) { auto Pos = InstantiatedFromUsingDecl.find(UUD); @@ -1548,8 +1524,14 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { return Target->getHalfFormat(); case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); - case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); - case BuiltinType::Float128: return Target->getFloat128Format(); + case BuiltinType::LongDouble: + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) + return AuxTarget->getLongDoubleFormat(); + return Target->getLongDoubleFormat(); + case BuiltinType::Float128: + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) + return AuxTarget->getFloat128Format(); + return Target->getFloat128Format(); } } @@ -1610,8 +1592,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { if (BaseT.getQualifiers().hasUnaligned()) Align = Target->getCharWidth(); if (const auto *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasGlobalStorage() && !ForAlignof) - Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); + if (VD->hasGlobalStorage() && !ForAlignof) { + uint64_t TypeSize = getTypeSize(T.getTypePtr()); + Align = std::max(Align, getTargetInfo().getMinGlobalAlign(TypeSize)); + } } } @@ -1916,8 +1900,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; case BuiltinType::Float16: case BuiltinType::Half: - Width = Target->getHalfWidth(); - Align = Target->getHalfAlign(); + if (Target->hasFloat16Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getHalfWidth(); + Align = Target->getHalfAlign(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getHalfWidth(); + Align = AuxTarget->getHalfAlign(); + } break; case BuiltinType::Float: Width = Target->getFloatWidth(); @@ -1928,12 +1920,27 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = Target->getDoubleAlign(); break; case BuiltinType::LongDouble: - Width = Target->getLongDoubleWidth(); - Align = Target->getLongDoubleAlign(); + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() || + Target->getLongDoubleAlign() != AuxTarget->getLongDoubleAlign())) { + Width = AuxTarget->getLongDoubleWidth(); + Align = AuxTarget->getLongDoubleAlign(); + } else { + Width = Target->getLongDoubleWidth(); + Align = Target->getLongDoubleAlign(); + } break; case BuiltinType::Float128: - Width = Target->getFloat128Width(); - Align = Target->getFloat128Align(); + if (Target->hasFloat128Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getFloat128Width(); + Align = Target->getFloat128Align(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getFloat128Width(); + Align = AuxTarget->getFloat128Align(); + } break; case BuiltinType::NullPtr: Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) @@ -2057,6 +2064,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Paren: return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr()); + case Type::MacroQualified: + return getTypeInfo( + cast<MacroQualifiedType>(T)->getUnderlyingType().getTypePtr()); + case Type::ObjCTypeParam: return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr()); @@ -2134,7 +2145,7 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else { - UnadjustedAlign = getTypeAlign(T); + UnadjustedAlign = getTypeAlign(T->getUnqualifiedDesugaredType()); } MemoizedUnadjustedAlign[T] = UnadjustedAlign; @@ -2233,7 +2244,8 @@ unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const { /// getAlignOfGlobalVar - Return the alignment in bits that should be given /// to a global variable of the specified type. unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { - return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign()); + uint64_t TypeSize = getTypeSize(T.getTypePtr()); + return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign(TypeSize)); } /// getAlignOfGlobalVarInChars - Return the alignment in characters that @@ -2574,7 +2586,7 @@ ASTContext::getBlockVarCopyInit(const VarDecl*VD) const { return {nullptr, false}; } -/// Set the copy inialization expression of a block var decl. +/// Set the copy initialization expression of a block var decl. void ASTContext::setBlockVarCopyInit(const VarDecl*VD, Expr *CopyExpr, bool CanThrow) { assert(VD && CopyExpr && "Passed null params"); @@ -2763,6 +2775,12 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec( return getParenType( getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI)); + // Might be wrapped in a macro qualified type. + if (const auto *MQT = dyn_cast<MacroQualifiedType>(Orig)) + return getMacroQualifiedType( + getFunctionTypeWithExceptionSpec(MQT->getUnderlyingType(), ESI), + MQT->getMacroIdentifier()); + // Might have a calling-convention attribute. if (const auto *AT = dyn_cast<AttributedType>(Orig)) return getAttributedType( @@ -2772,7 +2790,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec( // Anything else must be a function type. Rebuild it with the new exception // specification. - const auto *Proto = cast<FunctionProtoType>(Orig); + const auto *Proto = Orig->getAs<FunctionProtoType>(); return getFunctionType( Proto->getReturnType(), Proto->getParamTypes(), Proto->getExtProtoInfo().withExceptionSpec(ESI)); @@ -3739,7 +3757,10 @@ QualType ASTContext::getFunctionTypeInternal( break; } - case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue: + case EST_DynamicNone: + case EST_BasicNoexcept: + case EST_NoexceptTrue: + case EST_NoThrow: CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept; break; @@ -3938,7 +3959,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind, QualType canon = getCanonicalType(equivalentType); type = new (*this, TypeAlignment) - AttributedType(canon, attrKind, modifiedType, equivalentType); + AttributedType(canon, attrKind, modifiedType, equivalentType); Types.push_back(type); AttributedTypes.InsertNode(type, insertPos); @@ -4219,6 +4240,19 @@ ASTContext::getParenType(QualType InnerType) const { return QualType(T, 0); } +QualType +ASTContext::getMacroQualifiedType(QualType UnderlyingTy, + const IdentifierInfo *MacroII) const { + QualType Canon = UnderlyingTy; + if (!Canon.isCanonical()) + Canon = getCanonicalType(UnderlyingTy); + + auto *newType = new (*this, TypeAlignment) + MacroQualifiedType(UnderlyingTy, Canon, MacroII); + Types.push_back(newType); + return QualType(newType, 0); +} + QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, @@ -4356,7 +4390,13 @@ QualType ASTContext::getPackExpansionType(QualType Pattern, llvm::FoldingSetNodeID ID; PackExpansionType::Profile(ID, Pattern, NumExpansions); - assert(Pattern->containsUnexpandedParameterPack() && + // A deduced type can deduce to a pack, eg + // auto ...x = some_pack; + // That declaration isn't (yet) valid, but is created as part of building an + // init-capture pack: + // [...x = some_pack] {} + assert((Pattern->containsUnexpandedParameterPack() || + Pattern->getContainedDeducedType()) && "Pack expansions must expand one or more parameter packs"); void *InsertPos = nullptr; PackExpansionType *T @@ -4856,19 +4896,20 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent) const { + bool IsDependent, bool IsPack) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, Keyword, IsDependent); + AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); auto *AT = new (*this, TypeAlignment) - AutoType(DeducedType, Keyword, IsDependent); + AutoType(DeducedType, Keyword, IsDependent, IsPack); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -4930,7 +4971,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - /*dependent*/false), + /*dependent*/false, /*pack*/false), 0); return AutoDeductTy; } @@ -5218,6 +5259,11 @@ ASTContext::getNameForTemplate(TemplateName Name, return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *Storage = Name.getAsAssumedTemplateName(); + return DeclarationNameInfo(Storage->getDeclName(), NameLoc); + } + case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); DeclarationName DName; @@ -5265,7 +5311,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { } case TemplateName::OverloadedTemplate: - llvm_unreachable("cannot canonicalize overloaded template"); + case TemplateName::AssumedTemplate: + llvm_unreachable("cannot canonicalize unresolved template"); case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); @@ -5609,6 +5656,12 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const { return -1; } +int ASTContext::getFloatingTypeSemanticOrder(QualType LHS, QualType RHS) const { + if (&getFloatTypeSemantics(LHS) == &getFloatTypeSemantics(RHS)) + return 0; + return getFloatingTypeOrder(LHS, RHS); +} + /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. @@ -6283,12 +6336,13 @@ void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, // Encode type qualifer, 'in', 'inout', etc. for the parameter. getObjCEncodingForTypeQualifier(QT, S); // Encode parameter type. - getObjCEncodingForTypeImpl(T, S, true, true, nullptr, - true /*OutermostType*/, - false /*EncodingProperty*/, - false /*StructField*/, - Extended /*EncodeBlockParameters*/, - Extended /*EncodeClassNames*/); + ObjCEncOptions Options = ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(); + if (Extended) + Options.setEncodeBlockParameters().setEncodeClassNames(); + getObjCEncodingForTypeImpl(T, S, Options, /*Field=*/nullptr); } /// getObjCEncodingForMethodDecl - Return the encoded type for this method @@ -6480,9 +6534,12 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, true, true, Field, - true /* outermost type */, false, false, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType(), + Field, NotEncodedT); } void ASTContext::getObjCEncodingForPropertyType(QualType T, @@ -6490,9 +6547,13 @@ void ASTContext::getObjCEncodingForPropertyType(QualType T, // Encode result type. // GCC has some special rules regarding encoding of properties which // closely resembles encoding of ivars. - getObjCEncodingForTypeImpl(T, S, true, true, nullptr, - true /* outermost type */, - true /* encoding property */); + getObjCEncodingForTypeImpl(T, S, + ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures() + .setIsOutermostType() + .setEncodingProperty(), + /*Field=*/nullptr); } static char getObjCEncodingForPrimitiveKind(const ASTContext *C, @@ -6639,16 +6700,9 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, } // FIXME: Use SmallString for accumulating string. -void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, - bool ExpandPointedToStructures, - bool ExpandStructures, +void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, + const ObjCEncOptions Options, const FieldDecl *FD, - bool OutermostType, - bool EncodingProperty, - bool StructField, - bool EncodeBlockParameters, - bool EncodeClassNames, - bool EncodePointerToObjCTypedef, QualType *NotEncodedT) const { CanQualType CT = getCanonicalType(T); switch (CT->getTypeClass()) { @@ -6665,14 +6719,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Complex: { const auto *CT = T->castAs<ComplexType>(); S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr); + getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } case Type::Atomic: { const auto *AT = T->castAs<AtomicType>(); S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr); + getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(), + /*Field=*/nullptr); return; } @@ -6698,11 +6754,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // the pointer itself gets ignored, _unless_ we are looking at a typedef! // Also, do not emit the 'r' for anything but the outermost type! if (isa<TypedefType>(T.getTypePtr())) { - if (OutermostType && T.isConstQualified()) { + if (Options.IsOutermostType() && T.isConstQualified()) { isReadOnly = true; S += 'r'; } - } else if (OutermostType) { + } else if (Options.IsOutermostType()) { QualType P = PointeeTy; while (P->getAs<PointerType>()) P = P->getAs<PointerType>()->getPointeeType(); @@ -6742,9 +6798,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '^'; getLegacyIntegralTypeEncoding(PointeeTy); - getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, - nullptr, false, false, false, false, false, false, - NotEncodedT); + ObjCEncOptions NewOptions; + if (Options.ExpandPointedToStructures()) + NewOptions.setExpandStructures(); + getObjCEncodingForTypeImpl(PointeeTy, S, NewOptions, + /*Field=*/nullptr, NotEncodedT); return; } @@ -6753,12 +6811,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::VariableArray: { const auto *AT = cast<ArrayType>(CT); - if (isa<IncompleteArrayType>(AT) && !StructField) { + if (isa<IncompleteArrayType>(AT) && !Options.IsStructField()) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; - getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD); + getObjCEncodingForTypeImpl( + AT->getElementType(), S, + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD); } else { S += '['; @@ -6771,10 +6830,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '0'; } - getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD, - false, false, false, false, false, false, - NotEncodedT); + getObjCEncodingForTypeImpl( + AT->getElementType(), S, + Options.keepingOnly(ObjCEncOptions().setExpandStructures()), FD, + NotEncodedT); S += ']'; } return; @@ -6800,7 +6859,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '?'; } - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; if (!RDecl->isUnion()) { getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT); @@ -6814,16 +6873,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Special case bit-fields. if (Field->isBitField()) { - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), Field); } else { QualType qt = Field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, - FD, /*OutermostType*/false, - /*EncodingProperty*/false, - /*StructField*/true, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl( + qt, S, + ObjCEncOptions().setExpandStructures().setIsStructField(), FD, + NotEncodedT); } } } @@ -6835,26 +6894,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::BlockPointer: { const auto *BT = T->castAs<BlockPointerType>(); S += "@?"; // Unlike a pointer-to-function, which is "^?". - if (EncodeBlockParameters) { + if (Options.EncodeBlockParameters()) { const auto *FT = BT->getPointeeType()->castAs<FunctionType>(); S += '<'; // Block return type - getObjCEncodingForTypeImpl( - FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures, - FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames, false, - NotEncodedT); + getObjCEncodingForTypeImpl(FT->getReturnType(), S, + Options.forComponentType(), FD, NotEncodedT); // Block self S += "@?"; // Block parameters if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) { for (const auto &I : FPT->param_types()) - getObjCEncodingForTypeImpl( - I, S, ExpandPointedToStructures, ExpandStructures, FD, - false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames, - false, NotEncodedT); + getObjCEncodingForTypeImpl(I, S, Options.forComponentType(), FD, + NotEncodedT); } S += '>'; } @@ -6882,18 +6935,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, ObjCInterfaceDecl *OI = T->castAs<ObjCObjectType>()->getInterface(); S += '{'; S += OI->getObjCRuntimeNameAsString(); - if (ExpandStructures) { + if (Options.ExpandStructures()) { S += '='; SmallVector<const ObjCIvarDecl*, 32> Ivars; DeepCollectObjCIvars(OI, true, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { const FieldDecl *Field = Ivars[i]; if (Field->isBitField()) - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), + Field); else - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD, - false, false, false, false, false, - EncodePointerToObjCTypedef, + getObjCEncodingForTypeImpl(Field->getType(), S, + ObjCEncOptions().setExpandStructures(), FD, NotEncodedT); } } @@ -6910,17 +6964,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { // FIXME: Consider if we need to output qualifiers for 'Class<p>'. - // Since this is a binary compatibility issue, need to consult with runtime - // folks. Fortunately, this is a *very* obscure construct. + // Since this is a binary compatibility issue, need to consult with + // runtime folks. Fortunately, this is a *very* obscure construct. S += '#'; return; } if (OPT->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty || EncodeClassNames) { + getObjCEncodingForTypeImpl( + getObjCIdType(), S, + Options.keepingOnly(ObjCEncOptions() + .setExpandPointedToStructures() + .setExpandStructures()), + FD); + if (FD || Options.EncodingProperty() || Options.EncodeClassNames()) { // Note that we do extended encoding of protocol qualifer list // Only when doing ivar or property encoding. S += '"'; @@ -6934,39 +6991,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - QualType PointeeTy = OPT->getPointeeType(); - if (!EncodingProperty && - isa<TypedefType>(PointeeTy.getTypePtr()) && - !EncodePointerToObjCTypedef) { - // Another historical/compatibility reason. - // We encode the underlying type which comes out as - // {...}; - S += '^'; - if (FD && OPT->getInterfaceDecl()) { - // Prevent recursive encoding of fields in some rare cases. - ObjCInterfaceDecl *OI = OPT->getInterfaceDecl(); - SmallVector<const ObjCIvarDecl*, 32> Ivars; - DeepCollectObjCIvars(OI, true, Ivars); - for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { - if (Ivars[i] == FD) { - S += '{'; - S += OI->getObjCRuntimeNameAsString(); - S += '}'; - return; - } - } - } - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, - nullptr, - false, false, false, false, false, - /*EncodePointerToObjCTypedef*/true); - return; - } - S += '@'; if (OPT->getInterfaceDecl() && - (FD || EncodingProperty || EncodeClassNames)) { + (FD || Options.EncodingProperty() || Options.EncodeClassNames())) { S += '"'; S += OPT->getInterfaceDecl()->getObjCRuntimeNameAsString(); for (const auto *I : OPT->quals()) { @@ -6980,7 +7007,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } // gcc just blithely ignores member pointers. - // FIXME: we shoul do better than that. 'M' is available. + // FIXME: we should do better than that. 'M' is available. case Type::MemberPointer: // This matches gcc's encoding, even though technically it is insufficient. //FIXME. We should do a better job than gcc. @@ -7142,11 +7169,9 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, } else { QualType qt = field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, FD, - /*OutermostType*/false, - /*EncodingProperty*/false, - /*StructField*/true, - false, false, false, NotEncodedT); + getObjCEncodingForTypeImpl( + qt, S, ObjCEncOptions().setExpandStructures().setIsStructField(), + FD, NotEncodedT); #ifndef NDEBUG CurOffs += getTypeSize(field->getType()); #endif @@ -7606,6 +7631,13 @@ ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, return TemplateName(OT); } +/// Retrieve a template name representing an unqualified-id that has been +/// assumed to name a template for ADL purposes. +TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { + auto *OT = new (*this) AssumedTemplateStorage(Name); + return TemplateName(OT); +} + /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. TemplateName @@ -8581,7 +8613,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->isVariadic() != rproto->isVariadic()) return {}; - if (lproto->getTypeQuals() != rproto->getTypeQuals()) + if (lproto->getMethodQuals() != rproto->getMethodQuals()) return {}; SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos; @@ -9246,7 +9278,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // Read the prefixed modifiers first. bool Done = false; #ifndef NDEBUG - bool IsSpecialLong = false; + bool IsSpecial = false; #endif while (!Done) { switch (*Str++) { @@ -9265,26 +9297,26 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Unsigned = true; break; case 'L': - assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers"); + assert(!IsSpecial && "Can't use 'L' with 'W', 'N', 'Z' or 'O' modifiers"); assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; case 'N': // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. - assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); #ifndef NDEBUG - IsSpecialLong = true; + IsSpecial = true; #endif if (Context.getTargetInfo().getLongWidth() == 32) ++HowLong; break; case 'W': // This modifier represents int64 type. - assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!"); #ifndef NDEBUG - IsSpecialLong = true; + IsSpecial = true; #endif switch (Context.getTargetInfo().getInt64Type()) { default: @@ -9297,6 +9329,38 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, break; } break; + case 'Z': + // This modifier represents int32 type. + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); + assert(HowLong == 0 && "Can't use both 'L' and 'Z' modifiers!"); + #ifndef NDEBUG + IsSpecial = true; + #endif + switch (Context.getTargetInfo().getIntTypeByWidth(32, true)) { + default: + llvm_unreachable("Unexpected integer type"); + case TargetInfo::SignedInt: + HowLong = 0; + break; + case TargetInfo::SignedLong: + HowLong = 1; + break; + case TargetInfo::SignedLongLong: + HowLong = 2; + break; + } + break; + case 'O': + assert(!IsSpecial && "Can't use two 'N', 'W', 'Z' or 'O' modifiers!"); + assert(HowLong == 0 && "Can't use both 'L' and 'O' modifiers!"); + #ifndef NDEBUG + IsSpecial = true; + #endif + if (Context.getLangOpts().OpenCL) + HowLong = 1; + else + HowLong = 2; + break; } } @@ -9518,6 +9582,10 @@ QualType ASTContext::GetBuiltinType(unsigned Id, GetBuiltinTypeError &Error, unsigned *IntegerConstantArgs) const { const char *TypeStr = BuiltinInfo.getTypeString(Id); + if (TypeStr[0] == '\0') { + Error = GE_Missing_type; + return {}; + } SmallVector<QualType, 8> ArgTypes; @@ -9553,10 +9621,12 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - FunctionType::ExtInfo EI(CC_C); + bool Variadic = (TypeStr[0] == '.'); + + FunctionType::ExtInfo EI(getDefaultCallingConvention( + Variadic, /*IsCXXMethod=*/false, /*IsBuiltin=*/true)); if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); - bool Variadic = (TypeStr[0] == '.'); // We really shouldn't be making a no-proto type here. if (ArgTypes.empty() && Variadic && !getLangOpts().CPlusPlus) @@ -9784,12 +9854,12 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; } else if (isa<PragmaCommentDecl>(D)) return true; - else if (isa<OMPThreadPrivateDecl>(D)) - return true; else if (isa<PragmaDetectMismatchDecl>(D)) return true; else if (isa<OMPThreadPrivateDecl>(D)) return !D->getDeclContext()->isDependentContext(); + else if (isa<OMPAllocateDecl>(D)) + return !D->getDeclContext()->isDependentContext(); else if (isa<OMPDeclareReductionDecl>(D)) return !D->getDeclContext()->isDependentContext(); else if (isa<ImportDecl>(D)) @@ -9931,34 +10001,39 @@ void ASTContext::forEachMultiversionedFunctionVersion( } CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, - bool IsCXXMethod) const { + bool IsCXXMethod, + bool IsBuiltin) const { // Pass through to the C++ ABI object if (IsCXXMethod) return ABI->getDefaultMethodCallConv(IsVariadic); - switch (LangOpts.getDefaultCallingConv()) { - case LangOptions::DCC_None: - break; - case LangOptions::DCC_CDecl: - return CC_C; - case LangOptions::DCC_FastCall: - if (getTargetInfo().hasFeature("sse2") && !IsVariadic) - return CC_X86FastCall; - break; - case LangOptions::DCC_StdCall: - if (!IsVariadic) - return CC_X86StdCall; - break; - case LangOptions::DCC_VectorCall: - // __vectorcall cannot be applied to variadic functions. - if (!IsVariadic) - return CC_X86VectorCall; - break; - case LangOptions::DCC_RegCall: - // __regcall cannot be applied to variadic functions. - if (!IsVariadic) - return CC_X86RegCall; - break; + // Builtins ignore user-specified default calling convention and remain the + // Target's default calling convention. + if (!IsBuiltin) { + switch (LangOpts.getDefaultCallingConv()) { + case LangOptions::DCC_None: + break; + case LangOptions::DCC_CDecl: + return CC_C; + case LangOptions::DCC_FastCall: + if (getTargetInfo().hasFeature("sse2") && !IsVariadic) + return CC_X86FastCall; + break; + case LangOptions::DCC_StdCall: + if (!IsVariadic) + return CC_X86StdCall; + break; + case LangOptions::DCC_VectorCall: + // __vectorcall cannot be applied to variadic functions. + if (!IsVariadic) + return CC_X86VectorCall; + break; + case LangOptions::DCC_RegCall: + // __regcall cannot be applied to variadic functions. + if (!IsVariadic) + return CC_X86RegCall; + break; + } } return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown); } @@ -9978,8 +10053,10 @@ VTableContextBase *ASTContext::getVTableContext() { return VTContext.get(); } -MangleContext *ASTContext::createMangleContext() { - switch (Target->getCXXABI().getKind()) { +MangleContext *ASTContext::createMangleContext(const TargetInfo *T) { + if (!T) + T = Target; + switch (T->getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericItanium: case TargetCXXABI::GenericARM: @@ -10010,8 +10087,7 @@ size_t ASTContext::getSideTableAllocatedMemory() const { llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + llvm::capacity_in_bytes(OverriddenMethods) + llvm::capacity_in_bytes(Types) + - llvm::capacity_in_bytes(VariableArrayTypes) + - llvm::capacity_in_bytes(ClassScopeSpecializationPattern); + llvm::capacity_in_bytes(VariableArrayTypes); } /// getIntTypeForBitwidth - @@ -10140,6 +10216,31 @@ ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, return MaterializedTemporaryValues.lookup(E); } +QualType ASTContext::getStringLiteralArrayType(QualType EltTy, + unsigned Length) const { + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). + if (getLangOpts().CPlusPlus || getLangOpts().ConstStrings) + EltTy = EltTy.withConst(); + + EltTy = adjustStringLiteralBaseType(EltTy); + + // Get an array type for the string, according to C99 6.4.5. This includes + // the null terminator character. + return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1), + ArrayType::Normal, /*IndexTypeQuals*/ 0); +} + +StringLiteral * +ASTContext::getPredefinedStringLiteralFromCache(StringRef Key) const { + StringLiteral *&Result = StringLiteralCache[Key]; + if (!Result) + Result = StringLiteral::Create( + *this, Key, StringLiteral::Ascii, + /*Pascal*/ false, getStringLiteralArrayType(CharTy, Key.size()), + SourceLocation()); + return Result; +} + bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { const llvm::Triple &T = getTargetInfo().getTriple(); if (!T.isOSDarwin()) @@ -10485,7 +10586,13 @@ unsigned char ASTContext::getFixedPointIBits(QualType Ty) const { } FixedPointSemantics ASTContext::getFixedPointSemantics(QualType Ty) const { - assert(Ty->isFixedPointType()); + assert((Ty->isFixedPointType() || Ty->isIntegerType()) && + "Can only get the fixed point semantics for a " + "fixed point or integer type."); + if (Ty->isIntegerType()) + return FixedPointSemantics::GetIntegerSemantics(getIntWidth(Ty), + Ty->isSignedIntegerType()); + bool isSigned = Ty->isSignedFixedPointType(); return FixedPointSemantics( static_cast<unsigned>(getTypeSize(Ty)), getFixedPointScale(Ty), isSigned, @@ -10502,3 +10609,38 @@ APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const { assert(Ty->isFixedPointType()); return APFixedPoint::getMin(getFixedPointSemantics(Ty)); } + +QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const { + assert(Ty->isUnsignedFixedPointType() && + "Expected unsigned fixed point type"); + const auto *BTy = Ty->getAs<BuiltinType>(); + + switch (BTy->getKind()) { + case BuiltinType::UShortAccum: + return ShortAccumTy; + case BuiltinType::UAccum: + return AccumTy; + case BuiltinType::ULongAccum: + return LongAccumTy; + case BuiltinType::SatUShortAccum: + return SatShortAccumTy; + case BuiltinType::SatUAccum: + return SatAccumTy; + case BuiltinType::SatULongAccum: + return SatLongAccumTy; + case BuiltinType::UShortFract: + return ShortFractTy; + case BuiltinType::UFract: + return FractTy; + case BuiltinType::ULongFract: + return LongFractTy; + case BuiltinType::SatUShortFract: + return SatShortFractTy; + case BuiltinType::SatUFract: + return SatFractTy; + case BuiltinType::SatULongFract: + return SatLongFractTy; + default: + llvm_unreachable("Unexpected unsigned fixed point type"); + } +} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index dd05855585721..15df865852941 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -1,9 +1,8 @@ //===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -42,6 +41,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { QT = PT->desugar(); continue; } + // ... or a macro defined type ... + if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Ty)) { + QT = MDT->desugar(); + continue; + } // ...or a substituted template type parameter ... if (const SubstTemplateTypeParmType *ST = dyn_cast<SubstTemplateTypeParmType>(Ty)) { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index b52ec21943e6d..22196a1a26004 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -1,9 +1,8 @@ //===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -12,21 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTDumper.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ASTDumperUtils.h" -#include "clang/AST/Attr.h" -#include "clang/AST/AttrVisitor.h" -#include "clang/AST/CommentVisitor.h" -#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclOpenMP.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/LocInfoType.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TemplateArgumentVisitor.h" -#include "clang/AST/TextNodeDumper.h" -#include "clang/AST/TypeVisitor.h" +#include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" @@ -34,345 +22,8 @@ using namespace clang; using namespace clang::comments; -//===----------------------------------------------------------------------===// -// ASTDumper Visitor -//===----------------------------------------------------------------------===// - -namespace { - - class ASTDumper - : public ConstDeclVisitor<ASTDumper>, - public ConstStmtVisitor<ASTDumper>, - public ConstCommentVisitor<ASTDumper, void, const FullComment *>, - public TypeVisitor<ASTDumper>, - public ConstAttrVisitor<ASTDumper>, - public ConstTemplateArgumentVisitor<ASTDumper> { - - TextNodeDumper NodeDumper; - - raw_ostream &OS; - - /// The policy to use for printing; can be defaulted. - PrintingPolicy PrintPolicy; - - /// Indicates whether we should trigger deserialization of nodes that had - /// not already been loaded. - bool Deserialize = false; - - const bool ShowColors; - - /// Dump a child of the current node. - template<typename Fn> void dumpChild(Fn DoDumpChild) { - NodeDumper.AddChild(DoDumpChild); - } - template <typename Fn> void dumpChild(StringRef Label, Fn DoDumpChild) { - NodeDumper.AddChild(Label, DoDumpChild); - } - - public: - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM) - : ASTDumper(OS, Traits, SM, - SM && SM->getDiagnostics().getShowColors()) {} - - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM, bool ShowColors) - : ASTDumper(OS, Traits, SM, ShowColors, LangOptions()) {} - ASTDumper(raw_ostream &OS, const CommandTraits *Traits, - const SourceManager *SM, bool ShowColors, - const PrintingPolicy &PrintPolicy) - : NodeDumper(OS, ShowColors, SM, PrintPolicy, Traits), OS(OS), - PrintPolicy(PrintPolicy), ShowColors(ShowColors) {} - - void setDeserialize(bool D) { Deserialize = D; } - - void dumpDecl(const Decl *D); - void dumpStmt(const Stmt *S, StringRef Label = {}); - - // Utilities - void dumpTypeAsChild(QualType T); - void dumpTypeAsChild(const Type *T); - void dumpDeclContext(const DeclContext *DC); - void dumpLookups(const DeclContext *DC, bool DumpDecls); - void dumpAttr(const Attr *A); - - // C++ Utilities - void dumpCXXCtorInitializer(const CXXCtorInitializer *Init); - void dumpTemplateParameters(const TemplateParameterList *TPL); - void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI); - void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, - const Decl *From = nullptr, - const char *Label = nullptr); - void dumpTemplateArgumentList(const TemplateArgumentList &TAL); - void dumpTemplateArgument(const TemplateArgument &A, - SourceRange R = SourceRange(), - const Decl *From = nullptr, - const char *Label = nullptr); - template <typename SpecializationDecl> - void dumpTemplateDeclSpecialization(const SpecializationDecl *D, - bool DumpExplicitInst, - bool DumpRefOnly); - template <typename TemplateDecl> - void dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); - - // Objective-C utilities. - void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams); - - // Types - void VisitComplexType(const ComplexType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitLocInfoType(const LocInfoType *T) { - dumpTypeAsChild(T->getTypeSourceInfo()->getType()); - } - void VisitPointerType(const PointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitBlockPointerType(const BlockPointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitReferenceType(const ReferenceType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitMemberPointerType(const MemberPointerType *T) { - dumpTypeAsChild(T->getClass()); - dumpTypeAsChild(T->getPointeeType()); - } - void VisitArrayType(const ArrayType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitVariableArrayType(const VariableArrayType *T) { - VisitArrayType(T); - dumpStmt(T->getSizeExpr()); - } - void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { - dumpTypeAsChild(T->getElementType()); - dumpStmt(T->getSizeExpr()); - } - void VisitDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { - dumpTypeAsChild(T->getElementType()); - dumpStmt(T->getSizeExpr()); - } - void VisitVectorType(const VectorType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitFunctionType(const FunctionType *T) { - dumpTypeAsChild(T->getReturnType()); - } - void VisitFunctionProtoType(const FunctionProtoType *T) { - VisitFunctionType(T); - for (QualType PT : T->getParamTypes()) - dumpTypeAsChild(PT); - if (T->getExtProtoInfo().Variadic) - dumpChild([=] { OS << "..."; }); - } - void VisitTypeOfExprType(const TypeOfExprType *T) { - dumpStmt(T->getUnderlyingExpr()); - } - void VisitDecltypeType(const DecltypeType *T) { - dumpStmt(T->getUnderlyingExpr()); - } - void VisitUnaryTransformType(const UnaryTransformType *T) { - dumpTypeAsChild(T->getBaseType()); - } - void VisitAttributedType(const AttributedType *T) { - // FIXME: AttrKind - dumpTypeAsChild(T->getModifiedType()); - } - void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { - dumpTypeAsChild(T->getReplacedParameter()); - } - void VisitSubstTemplateTypeParmPackType( - const SubstTemplateTypeParmPackType *T) { - dumpTypeAsChild(T->getReplacedParameter()); - dumpTemplateArgument(T->getArgumentPack()); - } - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (auto &Arg : *T) - dumpTemplateArgument(Arg); - if (T->isTypeAlias()) - dumpTypeAsChild(T->getAliasedType()); - } - void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - dumpTypeAsChild(T->getPointeeType()); - } - void VisitAtomicType(const AtomicType *T) { - dumpTypeAsChild(T->getValueType()); - } - void VisitPipeType(const PipeType *T) { - dumpTypeAsChild(T->getElementType()); - } - void VisitAdjustedType(const AdjustedType *T) { - dumpTypeAsChild(T->getOriginalType()); - } - void VisitPackExpansionType(const PackExpansionType *T) { - if (!T->isSugared()) - dumpTypeAsChild(T->getPattern()); - } - // FIXME: ElaboratedType, DependentNameType, - // DependentTemplateSpecializationType, ObjCObjectType - - // Decls - void VisitLabelDecl(const LabelDecl *D); - void VisitTypedefDecl(const TypedefDecl *D); - void VisitEnumDecl(const EnumDecl *D); - void VisitRecordDecl(const RecordDecl *D); - void VisitEnumConstantDecl(const EnumConstantDecl *D); - void VisitIndirectFieldDecl(const IndirectFieldDecl *D); - void VisitFunctionDecl(const FunctionDecl *D); - void VisitFieldDecl(const FieldDecl *D); - void VisitVarDecl(const VarDecl *D); - void VisitDecompositionDecl(const DecompositionDecl *D); - void VisitBindingDecl(const BindingDecl *D); - void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D); - void VisitImportDecl(const ImportDecl *D); - void VisitPragmaCommentDecl(const PragmaCommentDecl *D); - void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D); - void VisitCapturedDecl(const CapturedDecl *D); - - // OpenMP decls - void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); - void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D); - void VisitOMPRequiresDecl(const OMPRequiresDecl *D); - void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D); - - // C++ Decls - void VisitNamespaceDecl(const NamespaceDecl *D); - void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D); - void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D); - void VisitTypeAliasDecl(const TypeAliasDecl *D); - void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D); - void VisitCXXRecordDecl(const CXXRecordDecl *D); - void VisitStaticAssertDecl(const StaticAssertDecl *D); - void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); - void VisitClassTemplateDecl(const ClassTemplateDecl *D); - void VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D); - void VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D); - void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D); - void VisitVarTemplateDecl(const VarTemplateDecl *D); - void VisitVarTemplateSpecializationDecl( - const VarTemplateSpecializationDecl *D); - void VisitVarTemplatePartialSpecializationDecl( - const VarTemplatePartialSpecializationDecl *D); - void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); - void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); - void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); - void VisitUsingDecl(const UsingDecl *D); - void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); - void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); - void VisitUsingShadowDecl(const UsingShadowDecl *D); - void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D); - void VisitLinkageSpecDecl(const LinkageSpecDecl *D); - void VisitAccessSpecDecl(const AccessSpecDecl *D); - void VisitFriendDecl(const FriendDecl *D); - - // ObjC Decls - void VisitObjCIvarDecl(const ObjCIvarDecl *D); - void VisitObjCMethodDecl(const ObjCMethodDecl *D); - void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D); - void VisitObjCCategoryDecl(const ObjCCategoryDecl *D); - void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D); - void VisitObjCProtocolDecl(const ObjCProtocolDecl *D); - void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D); - void VisitObjCImplementationDecl(const ObjCImplementationDecl *D); - void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D); - void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); - void Visit(const BlockDecl::Capture &C); - void VisitBlockDecl(const BlockDecl *D); - - // Stmts. - void VisitDeclStmt(const DeclStmt *Node); - void VisitAttributedStmt(const AttributedStmt *Node); - void VisitCXXCatchStmt(const CXXCatchStmt *Node); - void VisitCapturedStmt(const CapturedStmt *Node); - - // OpenMP - void Visit(const OMPClause *C); - void VisitOMPExecutableDirective(const OMPExecutableDirective *Node); - - // Exprs - void VisitInitListExpr(const InitListExpr *ILE); - void VisitBlockExpr(const BlockExpr *Node); - void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); - void VisitGenericSelectionExpr(const GenericSelectionExpr *E); - - // C++ - void VisitLambdaExpr(const LambdaExpr *Node) { - dumpDecl(Node->getLambdaClass()); - } - void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); - - // ObjC - void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); - - // Comments. - void dumpComment(const Comment *C, const FullComment *FC); - - void VisitExpressionTemplateArgument(const TemplateArgument &TA) { - dumpStmt(TA.getAsExpr()); - } - void VisitPackTemplateArgument(const TemplateArgument &TA) { - for (const auto &TArg : TA.pack_elements()) - dumpTemplateArgument(TArg); - } - -// Implements Visit methods for Attrs. -#include "clang/AST/AttrNodeTraverse.inc" - }; -} - -//===----------------------------------------------------------------------===// -// Utilities -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpTypeAsChild(QualType T) { - SplitQualType SQT = T.split(); - if (!SQT.Quals.hasQualifiers()) - return dumpTypeAsChild(SQT.Ty); - - dumpChild([=] { - NodeDumper.Visit(T); - dumpTypeAsChild(T.split().Ty); - }); -} - -void ASTDumper::dumpTypeAsChild(const Type *T) { - dumpChild([=] { - NodeDumper.Visit(T); - if (!T) - return; - TypeVisitor<ASTDumper>::Visit(T); - - QualType SingleStepDesugar = - T->getLocallyUnqualifiedSingleStepDesugaredType(); - if (SingleStepDesugar != QualType(T, 0)) - dumpTypeAsChild(SingleStepDesugar); - }); -} - -void ASTDumper::dumpDeclContext(const DeclContext *DC) { - if (!DC) - return; - - for (auto *D : (Deserialize ? DC->decls() : DC->noload_decls())) - dumpDecl(D); - - if (DC->hasExternalLexicalStorage()) { - dumpChild([=] { - ColorScope Color(OS, ShowColors, UndeserializedColor); - OS << "<undeserialized declarations>"; - }); - } -} - void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { - dumpChild([=] { + NodeDumper.AddChild([=] { OS << "StoredDeclsMap "; NodeDumper.dumpBareDeclRef(cast<Decl>(DC)); @@ -384,14 +35,14 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); - auto Range = Deserialize + auto Range = getDeserialize() ? Primary->lookups() : Primary->noload_lookups(/*PreserveInternalState=*/true); for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { DeclarationName Name = I.getLookupName(); DeclContextLookupResult R = *I; - dumpChild([=] { + NodeDumper.AddChild([=] { OS << "DeclarationName "; { ColorScope Color(OS, ShowColors, DeclNameColor); @@ -400,7 +51,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); RI != RE; ++RI) { - dumpChild([=] { + NodeDumper.AddChild([=] { NodeDumper.dumpBareDeclRef(*RI); if ((*RI)->isHidden()) @@ -412,7 +63,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { if (Decl *Prev = D->getPreviousDecl()) DumpWithPrev(Prev); - dumpDecl(D); + Visit(D); }; DumpWithPrev(*RI); } @@ -422,7 +73,7 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { } if (HasUndeserializedLookups) { - dumpChild([=] { + NodeDumper.AddChild([=] { ColorScope Color(OS, ShowColors, UndeserializedColor); OS << "<undeserialized lookups>"; }); @@ -430,560 +81,12 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { }); } -void ASTDumper::dumpAttr(const Attr *A) { - dumpChild([=] { - NodeDumper.Visit(A); - ConstAttrVisitor<ASTDumper>::Visit(A); - }); -} - -//===----------------------------------------------------------------------===// -// C++ Utilities -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { - dumpChild([=] { - NodeDumper.Visit(Init); - dumpStmt(Init->getInit()); - }); -} - -void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { - if (!TPL) - return; - - for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end(); - I != E; ++I) - dumpDecl(*I); -} - -void ASTDumper::dumpTemplateArgumentListInfo( - const TemplateArgumentListInfo &TALI) { - for (unsigned i = 0, e = TALI.size(); i < e; ++i) - dumpTemplateArgumentLoc(TALI[i]); -} - -void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A, - const Decl *From, const char *Label) { - dumpTemplateArgument(A.getArgument(), A.getSourceRange(), From, Label); -} - -void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { - for (unsigned i = 0, e = TAL.size(); i < e; ++i) - dumpTemplateArgument(TAL[i]); -} - -void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R, - const Decl *From, const char *Label) { - dumpChild([=] { - NodeDumper.Visit(A, R, From, Label); - ConstTemplateArgumentVisitor<ASTDumper>::Visit(A); - }); -} - -//===----------------------------------------------------------------------===// -// Objective-C Utilities -//===----------------------------------------------------------------------===// -void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) { - if (!typeParams) - return; - - for (auto typeParam : *typeParams) { - dumpDecl(typeParam); - } -} - -//===----------------------------------------------------------------------===// -// Decl dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpDecl(const Decl *D) { - dumpChild([=] { - NodeDumper.Visit(D); - if (!D) - return; - - ConstDeclVisitor<ASTDumper>::Visit(D); - - for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; - ++I) - dumpAttr(*I); - - if (const FullComment *Comment = - D->getASTContext().getLocalCommentForDeclUncached(D)) - dumpComment(Comment, Comment); - - // Decls within functions are visited by the body. - if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) { - auto DC = dyn_cast<DeclContext>(D); - if (DC && - (DC->hasExternalLexicalStorage() || - (Deserialize ? DC->decls_begin() != DC->decls_end() - : DC->noload_decls_begin() != DC->noload_decls_end()))) - dumpDeclContext(DC); - } - }); -} - -void ASTDumper::VisitLabelDecl(const LabelDecl *D) { NodeDumper.dumpName(D); } - -void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getUnderlyingType()); - if (D->isModulePrivate()) - OS << " __module_private__"; - dumpTypeAsChild(D->getUnderlyingType()); -} - -void ASTDumper::VisitEnumDecl(const EnumDecl *D) { - if (D->isScoped()) { - if (D->isScopedUsingClassTag()) - OS << " class"; - else - OS << " struct"; - } - NodeDumper.dumpName(D); - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isFixed()) - NodeDumper.dumpType(D->getIntegerType()); -} - -void ASTDumper::VisitRecordDecl(const RecordDecl *D) { - OS << ' ' << D->getKindName(); - NodeDumper.dumpName(D); - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isCompleteDefinition()) - OS << " definition"; -} - -void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (const Expr *Init = D->getInitExpr()) - dumpStmt(Init); -} - -void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - for (auto *Child : D->chain()) - NodeDumper.dumpDeclRef(Child); -} - -void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - StorageClass SC = D->getStorageClass(); - if (SC != SC_None) - OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - if (D->isInlineSpecified()) - OS << " inline"; - if (D->isVirtualAsWritten()) - OS << " virtual"; - if (D->isModulePrivate()) - OS << " __module_private__"; - - if (D->isPure()) - OS << " pure"; - if (D->isDefaulted()) { - OS << " default"; - if (D->isDeleted()) - OS << "_delete"; - } - if (D->isDeletedAsWritten()) - OS << " delete"; - if (D->isTrivial()) - OS << " trivial"; - - if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) { - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - switch (EPI.ExceptionSpec.Type) { - default: break; - case EST_Unevaluated: - OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl; - break; - case EST_Uninstantiated: - OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate; - break; - } - } - - if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - if (MD->size_overridden_methods() != 0) { - auto dumpOverride = [=](const CXXMethodDecl *D) { - SplitQualType T_split = D->getType().split(); - OS << D << " " << D->getParent()->getName() - << "::" << D->getNameAsString() << " '" - << QualType::getAsString(T_split, PrintPolicy) << "'"; - }; - - dumpChild([=] { - auto Overrides = MD->overridden_methods(); - OS << "Overrides: [ "; - dumpOverride(*Overrides.begin()); - for (const auto *Override : - llvm::make_range(Overrides.begin() + 1, Overrides.end())) { - OS << ", "; - dumpOverride(Override); - } - OS << " ]"; - }); - } - } - - if (const auto *FTSI = D->getTemplateSpecializationInfo()) - dumpTemplateArgumentList(*FTSI->TemplateArguments); - - if (!D->param_begin() && D->getNumParams()) - dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() << ">>"; }); - else - for (const ParmVarDecl *Parameter : D->parameters()) - dumpDecl(Parameter); - - if (const auto *C = dyn_cast<CXXConstructorDecl>(D)) - for (const auto *I : C->inits()) - dumpCXXCtorInitializer(I); - - if (D->doesThisDeclarationHaveABody()) - dumpStmt(D->getBody()); -} - -void ASTDumper::VisitFieldDecl(const FieldDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (D->isMutable()) - OS << " mutable"; - if (D->isModulePrivate()) - OS << " __module_private__"; - - if (D->isBitField()) - dumpStmt(D->getBitWidth()); - if (Expr *Init = D->getInClassInitializer()) - dumpStmt(Init); -} - -void ASTDumper::VisitVarDecl(const VarDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - StorageClass SC = D->getStorageClass(); - if (SC != SC_None) - OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - switch (D->getTLSKind()) { - case VarDecl::TLS_None: break; - case VarDecl::TLS_Static: OS << " tls"; break; - case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; - } - if (D->isModulePrivate()) - OS << " __module_private__"; - if (D->isNRVOVariable()) - OS << " nrvo"; - if (D->isInline()) - OS << " inline"; - if (D->isConstexpr()) - OS << " constexpr"; - if (D->hasInit()) { - switch (D->getInitStyle()) { - case VarDecl::CInit: OS << " cinit"; break; - case VarDecl::CallInit: OS << " callinit"; break; - case VarDecl::ListInit: OS << " listinit"; break; - } - dumpStmt(D->getInit()); - } -} - -void ASTDumper::VisitDecompositionDecl(const DecompositionDecl *D) { - VisitVarDecl(D); - for (auto *B : D->bindings()) - dumpDecl(B); -} - -void ASTDumper::VisitBindingDecl(const BindingDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (auto *E = D->getBinding()) - dumpStmt(E); -} - -void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { - dumpStmt(D->getAsmString()); -} - -void ASTDumper::VisitImportDecl(const ImportDecl *D) { - OS << ' ' << D->getImportedModule()->getFullModuleName(); -} - -void ASTDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { - OS << ' '; - switch (D->getCommentKind()) { - case PCK_Unknown: llvm_unreachable("unexpected pragma comment kind"); - case PCK_Compiler: OS << "compiler"; break; - case PCK_ExeStr: OS << "exestr"; break; - case PCK_Lib: OS << "lib"; break; - case PCK_Linker: OS << "linker"; break; - case PCK_User: OS << "user"; break; - } - StringRef Arg = D->getArg(); - if (!Arg.empty()) - OS << " \"" << Arg << "\""; -} - -void ASTDumper::VisitPragmaDetectMismatchDecl( - const PragmaDetectMismatchDecl *D) { - OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\""; -} - -void ASTDumper::VisitCapturedDecl(const CapturedDecl *D) { - dumpStmt(D->getBody()); -} - -//===----------------------------------------------------------------------===// -// OpenMP Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { - for (auto *E : D->varlists()) - dumpStmt(E); -} - -void ASTDumper::VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - OS << " combiner"; - NodeDumper.dumpPointer(D->getCombiner()); - if (const auto *Initializer = D->getInitializer()) { - OS << " initializer"; - NodeDumper.dumpPointer(Initializer); - switch (D->getInitializerKind()) { - case OMPDeclareReductionDecl::DirectInit: - OS << " omp_priv = "; - break; - case OMPDeclareReductionDecl::CopyInit: - OS << " omp_priv ()"; - break; - case OMPDeclareReductionDecl::CallInit: - break; - } - } - - dumpStmt(D->getCombiner()); - if (const auto *Initializer = D->getInitializer()) - dumpStmt(Initializer); -} - -void ASTDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) { - for (auto *C : D->clauselists()) { - dumpChild([=] { - if (!C) { - ColorScope Color(OS, ShowColors, NullColor); - OS << "<<<NULL>>> OMPClause"; - return; - } - { - ColorScope Color(OS, ShowColors, AttrColor); - StringRef ClauseName(getOpenMPClauseName(C->getClauseKind())); - OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper() - << ClauseName.drop_front() << "Clause"; - } - NodeDumper.dumpPointer(C); - NodeDumper.dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc())); - }); - } -} - -void ASTDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - dumpStmt(D->getInit()); -} - -//===----------------------------------------------------------------------===// -// C++ Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) { - NodeDumper.dumpName(D); - if (D->isInline()) - OS << " inline"; - if (!D->isOriginalNamespace()) - NodeDumper.dumpDeclRef(D->getOriginalNamespace(), "original"); -} - -void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getNominatedNamespace()); -} - -void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getAliasedNamespace()); -} - -void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getUnderlyingType()); - dumpTypeAsChild(D->getUnderlyingType()); -} - -void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); - dumpDecl(D->getTemplatedDecl()); -} - -void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { - VisitRecordDecl(D); - if (!D->isCompleteDefinition()) - return; - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "DefinitionData"; - } -#define FLAG(fn, name) if (D->fn()) OS << " " #name; - FLAG(isParsingBaseSpecifiers, parsing_base_specifiers); - - FLAG(isGenericLambda, generic); - FLAG(isLambda, lambda); - - FLAG(canPassInRegisters, pass_in_registers); - FLAG(isEmpty, empty); - FLAG(isAggregate, aggregate); - FLAG(isStandardLayout, standard_layout); - FLAG(isTriviallyCopyable, trivially_copyable); - FLAG(isPOD, pod); - FLAG(isTrivial, trivial); - FLAG(isPolymorphic, polymorphic); - FLAG(isAbstract, abstract); - FLAG(isLiteral, literal); - - FLAG(hasUserDeclaredConstructor, has_user_declared_ctor); - FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor); - FLAG(hasMutableFields, has_mutable_fields); - FLAG(hasVariantMembers, has_variant_members); - FLAG(allowConstDefaultInit, can_const_default_init); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "DefaultConstructor"; - } - FLAG(hasDefaultConstructor, exists); - FLAG(hasTrivialDefaultConstructor, trivial); - FLAG(hasNonTrivialDefaultConstructor, non_trivial); - FLAG(hasUserProvidedDefaultConstructor, user_provided); - FLAG(hasConstexprDefaultConstructor, constexpr); - FLAG(needsImplicitDefaultConstructor, needs_implicit); - FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "CopyConstructor"; - } - FLAG(hasSimpleCopyConstructor, simple); - FLAG(hasTrivialCopyConstructor, trivial); - FLAG(hasNonTrivialCopyConstructor, non_trivial); - FLAG(hasUserDeclaredCopyConstructor, user_declared); - FLAG(hasCopyConstructorWithConstParam, has_const_param); - FLAG(needsImplicitCopyConstructor, needs_implicit); - FLAG(needsOverloadResolutionForCopyConstructor, - needs_overload_resolution); - if (!D->needsOverloadResolutionForCopyConstructor()) - FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted); - FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "MoveConstructor"; - } - FLAG(hasMoveConstructor, exists); - FLAG(hasSimpleMoveConstructor, simple); - FLAG(hasTrivialMoveConstructor, trivial); - FLAG(hasNonTrivialMoveConstructor, non_trivial); - FLAG(hasUserDeclaredMoveConstructor, user_declared); - FLAG(needsImplicitMoveConstructor, needs_implicit); - FLAG(needsOverloadResolutionForMoveConstructor, - needs_overload_resolution); - if (!D->needsOverloadResolutionForMoveConstructor()) - FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "CopyAssignment"; - } - FLAG(hasTrivialCopyAssignment, trivial); - FLAG(hasNonTrivialCopyAssignment, non_trivial); - FLAG(hasCopyAssignmentWithConstParam, has_const_param); - FLAG(hasUserDeclaredCopyAssignment, user_declared); - FLAG(needsImplicitCopyAssignment, needs_implicit); - FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution); - FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "MoveAssignment"; - } - FLAG(hasMoveAssignment, exists); - FLAG(hasSimpleMoveAssignment, simple); - FLAG(hasTrivialMoveAssignment, trivial); - FLAG(hasNonTrivialMoveAssignment, non_trivial); - FLAG(hasUserDeclaredMoveAssignment, user_declared); - FLAG(needsImplicitMoveAssignment, needs_implicit); - FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution); - }); - - dumpChild([=] { - { - ColorScope Color(OS, ShowColors, DeclKindNameColor); - OS << "Destructor"; - } - FLAG(hasSimpleDestructor, simple); - FLAG(hasIrrelevantDestructor, irrelevant); - FLAG(hasTrivialDestructor, trivial); - FLAG(hasNonTrivialDestructor, non_trivial); - FLAG(hasUserDeclaredDestructor, user_declared); - FLAG(needsImplicitDestructor, needs_implicit); - FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution); - if (!D->needsOverloadResolutionForDestructor()) - FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted); - }); - }); - - for (const auto &I : D->bases()) { - dumpChild([=] { - if (I.isVirtual()) - OS << "virtual "; - NodeDumper.dumpAccessSpecifier(I.getAccessSpecifier()); - NodeDumper.dumpType(I.getType()); - if (I.isPackExpansion()) - OS << "..."; - }); - } -} - -void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { - dumpStmt(D->getAssertExpr()); - dumpStmt(D->getMessage()); -} - template <typename SpecializationDecl> void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly) { bool DumpedAny = false; - for (auto *RedeclWithBadType : D->redecls()) { + for (const auto *RedeclWithBadType : D->redecls()) { // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). @@ -1007,7 +110,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, if (DumpRefOnly) NodeDumper.dumpDeclRef(Redecl); else - dumpDecl(Redecl); + Visit(Redecl); DumpedAny = true; break; case TSK_ExplicitSpecialization: @@ -1022,12 +125,11 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, template <typename TemplateDecl> void ASTDumper::dumpTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst) { - NodeDumper.dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); - dumpDecl(D->getTemplatedDecl()); + Visit(D->getTemplatedDecl()); - for (auto *Child : D->specializations()) + for (const auto *Child : D->specializations()) dumpTemplateDeclSpecialization(Child, DumpExplicitInst, !D->isCanonicalDecl()); } @@ -1043,500 +145,10 @@ void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { dumpTemplateDecl(D, false); } -void ASTDumper::VisitClassTemplateSpecializationDecl( - const ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); - dumpTemplateArgumentList(D->getTemplateArgs()); -} - -void ASTDumper::VisitClassTemplatePartialSpecializationDecl( - const ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - dumpTemplateParameters(D->getTemplateParameters()); -} - -void ASTDumper::VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D) { - dumpDecl(D->getSpecialization()); - if (D->hasExplicitTemplateArgs()) - dumpTemplateArgumentListInfo(D->templateArgs()); -} - void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D, false); } -void ASTDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); -} - -void ASTDumper::VisitVarTemplateSpecializationDecl( - const VarTemplateSpecializationDecl *D) { - dumpTemplateArgumentList(D->getTemplateArgs()); - VisitVarDecl(D); -} - -void ASTDumper::VisitVarTemplatePartialSpecializationDecl( - const VarTemplatePartialSpecializationDecl *D) { - dumpTemplateParameters(D->getTemplateParameters()); - VisitVarTemplateSpecializationDecl(D); -} - -void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { - if (D->wasDeclaredWithTypename()) - OS << " typename"; - else - OS << " class"; - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - if (D->hasDefaultArgument()) - dumpTemplateArgument(D->getDefaultArgument(), SourceRange(), - D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" - : "previous"); -} - -void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - NodeDumper.dumpType(D->getType()); - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - if (D->hasDefaultArgument()) - dumpTemplateArgument(D->getDefaultArgument(), SourceRange(), - D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" - : "previous"); -} - -void ASTDumper::VisitTemplateTemplateParmDecl( - const TemplateTemplateParmDecl *D) { - OS << " depth " << D->getDepth() << " index " << D->getIndex(); - if (D->isParameterPack()) - OS << " ..."; - NodeDumper.dumpName(D); - dumpTemplateParameters(D->getTemplateParameters()); - if (D->hasDefaultArgument()) - dumpTemplateArgumentLoc( - D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(), - D->defaultArgumentWasInherited() ? "inherited from" : "previous"); -} - -void ASTDumper::VisitUsingDecl(const UsingDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); -} - -void ASTDumper::VisitUnresolvedUsingTypenameDecl( - const UnresolvedUsingTypenameDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); -} - -void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) { - OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); - NodeDumper.dumpType(D->getType()); -} - -void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getTargetDecl()); - if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) - dumpTypeAsChild(TD->getTypeForDecl()); -} - -void ASTDumper::VisitConstructorUsingShadowDecl( - const ConstructorUsingShadowDecl *D) { - if (D->constructsVirtualBase()) - OS << " virtual"; - - dumpChild([=] { - OS << "target "; - NodeDumper.dumpBareDeclRef(D->getTargetDecl()); - }); - - dumpChild([=] { - OS << "nominated "; - NodeDumper.dumpBareDeclRef(D->getNominatedBaseClass()); - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getNominatedBaseClassShadowDecl()); - }); - - dumpChild([=] { - OS << "constructed "; - NodeDumper.dumpBareDeclRef(D->getConstructedBaseClass()); - OS << ' '; - NodeDumper.dumpBareDeclRef(D->getConstructedBaseClassShadowDecl()); - }); -} - -void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { - switch (D->getLanguage()) { - case LinkageSpecDecl::lang_c: OS << " C"; break; - case LinkageSpecDecl::lang_cxx: OS << " C++"; break; - } -} - -void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { - OS << ' '; - NodeDumper.dumpAccessSpecifier(D->getAccess()); -} - -void ASTDumper::VisitFriendDecl(const FriendDecl *D) { - if (TypeSourceInfo *T = D->getFriendType()) - NodeDumper.dumpType(T->getType()); - else - dumpDecl(D->getFriendDecl()); -} - -//===----------------------------------------------------------------------===// -// Obj-C Declarations -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - if (D->getSynthesize()) - OS << " synthesize"; - - switch (D->getAccessControl()) { - case ObjCIvarDecl::None: - OS << " none"; - break; - case ObjCIvarDecl::Private: - OS << " private"; - break; - case ObjCIvarDecl::Protected: - OS << " protected"; - break; - case ObjCIvarDecl::Public: - OS << " public"; - break; - case ObjCIvarDecl::Package: - OS << " package"; - break; - } -} - -void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { - if (D->isInstanceMethod()) - OS << " -"; - else - OS << " +"; - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getReturnType()); - - if (D->isThisDeclarationADefinition()) { - dumpDeclContext(D); - } else { - for (const ParmVarDecl *Parameter : D->parameters()) - dumpDecl(Parameter); - } - - if (D->isVariadic()) - dumpChild([=] { OS << "..."; }); - - if (D->hasBody()) - dumpStmt(D->getBody()); -} - -void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { - NodeDumper.dumpName(D); - switch (D->getVariance()) { - case ObjCTypeParamVariance::Invariant: - break; - - case ObjCTypeParamVariance::Covariant: - OS << " covariant"; - break; - - case ObjCTypeParamVariance::Contravariant: - OS << " contravariant"; - break; - } - - if (D->hasExplicitBound()) - OS << " bounded"; - NodeDumper.dumpType(D->getUnderlyingType()); -} - -void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); - NodeDumper.dumpDeclRef(D->getImplementation()); - for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), - E = D->protocol_end(); - I != E; ++I) - NodeDumper.dumpDeclRef(*I); - dumpObjCTypeParamList(D->getTypeParamList()); -} - -void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); - NodeDumper.dumpDeclRef(D->getCategoryDecl()); -} - -void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { - NodeDumper.dumpName(D); - - for (auto *Child : D->protocols()) - NodeDumper.dumpDeclRef(Child); -} - -void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getSuperClass(), "super"); - - NodeDumper.dumpDeclRef(D->getImplementation()); - for (auto *Child : D->protocols()) - NodeDumper.dumpDeclRef(Child); - dumpObjCTypeParamList(D->getTypeParamListAsWritten()); -} - -void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getSuperClass(), "super"); - NodeDumper.dumpDeclRef(D->getClassInterface()); - for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), - E = D->init_end(); - I != E; ++I) - dumpCXXCtorInitializer(*I); -} - -void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpDeclRef(D->getClassInterface()); -} - -void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { - NodeDumper.dumpName(D); - NodeDumper.dumpType(D->getType()); - - if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) - OS << " required"; - else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) - OS << " optional"; - - ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); - if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { - if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) - OS << " readonly"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) - OS << " assign"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) - OS << " readwrite"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) - OS << " retain"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) - OS << " copy"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) - OS << " nonatomic"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) - OS << " atomic"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) - OS << " weak"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) - OS << " strong"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) - OS << " unsafe_unretained"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_class) - OS << " class"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) - NodeDumper.dumpDeclRef(D->getGetterMethodDecl(), "getter"); - if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) - NodeDumper.dumpDeclRef(D->getSetterMethodDecl(), "setter"); - } -} - -void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { - NodeDumper.dumpName(D->getPropertyDecl()); - if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) - OS << " synthesize"; - else - OS << " dynamic"; - NodeDumper.dumpDeclRef(D->getPropertyDecl()); - NodeDumper.dumpDeclRef(D->getPropertyIvarDecl()); -} - -void ASTDumper::Visit(const BlockDecl::Capture &C) { - dumpChild([=] { - NodeDumper.Visit(C); - if (C.hasCopyExpr()) - dumpStmt(C.getCopyExpr()); - }); -} - -void ASTDumper::VisitBlockDecl(const BlockDecl *D) { - for (auto I : D->parameters()) - dumpDecl(I); - - if (D->isVariadic()) - dumpChild([=]{ OS << "..."; }); - - if (D->capturesCXXThis()) - dumpChild([=]{ OS << "capture this"; }); - - for (const auto &I : D->captures()) - Visit(I); - dumpStmt(D->getBody()); -} - -//===----------------------------------------------------------------------===// -// Stmt dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpStmt(const Stmt *S, StringRef Label) { - dumpChild(Label, [=] { - NodeDumper.Visit(S); - - if (!S) { - return; - } - - ConstStmtVisitor<ASTDumper>::Visit(S); - - // Some statements have custom mechanisms for dumping their children. - if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) { - return; - } - - for (const Stmt *SubStmt : S->children()) - dumpStmt(SubStmt); - }); -} - -void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { - for (DeclStmt::const_decl_iterator I = Node->decl_begin(), - E = Node->decl_end(); - I != E; ++I) - dumpDecl(*I); -} - -void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { - for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(), - E = Node->getAttrs().end(); - I != E; ++I) - dumpAttr(*I); -} - -void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { - dumpDecl(Node->getExceptionDecl()); -} - -void ASTDumper::VisitCapturedStmt(const CapturedStmt *Node) { - dumpDecl(Node->getCapturedDecl()); -} - -//===----------------------------------------------------------------------===// -// OpenMP dumping methods. -//===----------------------------------------------------------------------===// - -void ASTDumper::Visit(const OMPClause *C) { - dumpChild([=] { - NodeDumper.Visit(C); - for (auto *S : C->children()) - dumpStmt(S); - }); -} - -void ASTDumper::VisitOMPExecutableDirective( - const OMPExecutableDirective *Node) { - for (const auto *C : Node->clauses()) - Visit(C); -} - -//===----------------------------------------------------------------------===// -// Expr dumping methods. -//===----------------------------------------------------------------------===// - - -void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) { - if (auto *Filler = ILE->getArrayFiller()) { - dumpStmt(Filler, "array_filler"); - } -} - -void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { - dumpDecl(Node->getBlockDecl()); -} - -void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { - if (Expr *Source = Node->getSourceExpr()) - dumpStmt(Source); -} - -void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { - if (E->isResultDependent()) - OS << " result_dependent"; - dumpStmt(E->getControllingExpr()); - dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove - - for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { - dumpChild([=] { - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) { - OS << "case "; - NodeDumper.dumpType(TSI->getType()); - } else { - OS << "default"; - } - - if (!E->isResultDependent() && E->getResultIndex() == I) - OS << " selected"; - - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) - dumpTypeAsChild(TSI->getType()); - dumpStmt(E->getAssocExpr(I)); - }); - } -} - -//===----------------------------------------------------------------------===// -// C++ Expressions -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { - if (Node->isPartiallySubstituted()) - for (const auto &A : Node->getPartialArguments()) - dumpTemplateArgument(A); -} - -//===----------------------------------------------------------------------===// -// Obj-C Expressions -//===----------------------------------------------------------------------===// - -void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) { - if (const VarDecl *CatchParam = Node->getCatchParamDecl()) - dumpDecl(CatchParam); -} - -//===----------------------------------------------------------------------===// -// Comments -//===----------------------------------------------------------------------===// - -void ASTDumper::dumpComment(const Comment *C, const FullComment *FC) { - dumpChild([=] { - NodeDumper.Visit(C, FC); - if (!C) { - return; - } - ConstCommentVisitor<ASTDumper, void, const FullComment *>::visit(C, FC); - for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); - I != E; ++I) - dumpComment(*I, FC); - }); -} - //===----------------------------------------------------------------------===// // Type method implementations //===----------------------------------------------------------------------===// @@ -1551,7 +163,7 @@ LLVM_DUMP_METHOD void QualType::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void QualType::dump(llvm::raw_ostream &OS) const { ASTDumper Dumper(OS, nullptr, nullptr); - Dumper.dumpTypeAsChild(*this); + Dumper.Visit(*this); } LLVM_DUMP_METHOD void Type::dump() const { dump(llvm::errs()); } @@ -1566,13 +178,22 @@ LLVM_DUMP_METHOD void Type::dump(llvm::raw_ostream &OS) const { LLVM_DUMP_METHOD void Decl::dump() const { dump(llvm::errs()); } -LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize) const { - const ASTContext &Ctx = getASTContext(); +LLVM_DUMP_METHOD void Decl::dump(raw_ostream &OS, bool Deserialize, + ASTDumpOutputFormat Format) const { + ASTContext &Ctx = getASTContext(); const SourceManager &SM = Ctx.getSourceManager(); - ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, - SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); - P.setDeserialize(Deserialize); - P.dumpDecl(this); + + if (ADOF_JSON == Format) { + JSONDumper P(OS, SM, Ctx, Ctx.getPrintingPolicy(), + &Ctx.getCommentCommandTraits()); + (void)Deserialize; // FIXME? + P.Visit(this); + } else { + ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &SM, + SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); + P.setDeserialize(Deserialize); + P.Visit(this); + } } LLVM_DUMP_METHOD void Decl::dumpColor() const { @@ -1580,7 +201,7 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const { ASTDumper P(llvm::errs(), &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager(), /*ShowColors*/ true, Ctx.getPrintingPolicy()); - P.dumpDecl(this); + P.Visit(this); } LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { @@ -1611,22 +232,22 @@ LLVM_DUMP_METHOD void Stmt::dump(SourceManager &SM) const { LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { ASTDumper P(OS, nullptr, &SM); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const { ASTDumper P(OS, nullptr, nullptr); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dump() const { ASTDumper P(llvm::errs(), nullptr, nullptr); - P.dumpStmt(this); + P.Visit(this); } LLVM_DUMP_METHOD void Stmt::dumpColor() const { ASTDumper P(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); - P.dumpStmt(this); + P.Visit(this); } //===----------------------------------------------------------------------===// @@ -1648,7 +269,7 @@ void Comment::dump(raw_ostream &OS, const CommandTraits *Traits, if (!FC) return; ASTDumper D(OS, Traits, SM); - D.dumpComment(FC, FC); + D.Visit(FC, FC); } LLVM_DUMP_METHOD void Comment::dumpColor() const { @@ -1656,5 +277,5 @@ LLVM_DUMP_METHOD void Comment::dumpColor() const { if (!FC) return; ASTDumper D(llvm::errs(), nullptr, nullptr, /*ShowColors*/true); - D.dumpComment(FC, FC); + D.Visit(FC, FC); } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 44832557e97be..9d5dd84161dec 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1,9 +1,8 @@ //===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -13,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTImporter.h" -#include "clang/AST/ASTImporterLookupTable.h" +#include "clang/AST/ASTImporterSharedState.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTStructuralEquivalence.h" @@ -58,6 +57,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" @@ -135,25 +135,6 @@ namespace clang { To->setIsUsed(); } - // FIXME: Temporary until every import returns Expected. - template <> - LLVM_NODISCARD Error - ASTImporter::importInto(SourceLocation &To, const SourceLocation &From) { - To = Import(From); - if (From.isValid() && To.isInvalid()) - return llvm::make_error<ImportError>(); - return Error::success(); - } - // FIXME: Temporary until every import returns Expected. - template <> - LLVM_NODISCARD Error - ASTImporter::importInto(QualType &To, const QualType &From) { - To = Import(From); - if (!From.isNull() && To.isNull()) - return llvm::make_error<ImportError>(); - return Error::success(); - } - class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, ExpectedType>, public DeclVisitor<ASTNodeImporter, ExpectedDecl>, public StmtVisitor<ASTNodeImporter, ExpectedStmt> { @@ -168,32 +149,20 @@ namespace clang { // Use this to import pointers of specific type. template <typename ImportT> LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) { - auto ToI = Importer.Import(From); - if (!ToI && From) - return make_error<ImportError>(); - To = cast_or_null<ImportT>(ToI); - return Error::success(); - // FIXME: This should be the final code. - //auto ToOrErr = Importer.Import(From); - //if (ToOrErr) { - // To = cast_or_null<ImportT>(*ToOrErr); - //} - //return ToOrErr.takeError(); + auto ToOrErr = Importer.Import(From); + if (ToOrErr) + To = cast_or_null<ImportT>(*ToOrErr); + return ToOrErr.takeError(); } // Call the import function of ASTImporter for a baseclass of type `T` and // cast the return value to `T`. template <typename T> Expected<T *> import(T *From) { - auto *To = Importer.Import(From); - if (!To && From) - return make_error<ImportError>(); - return cast_or_null<T>(To); - // FIXME: This should be the final code. - //auto ToOrErr = Importer.Import(From); - //if (!ToOrErr) - // return ToOrErr.takeError(); - //return cast_or_null<T>(*ToOrErr); + auto ToOrErr = Importer.Import(From); + if (!ToOrErr) + return ToOrErr.takeError(); + return cast_or_null<T>(*ToOrErr); } template <typename T> @@ -204,13 +173,15 @@ namespace clang { // Call the import function of ASTImporter for type `T`. template <typename T> Expected<T> import(const T &From) { - T To = Importer.Import(From); - T DefaultT; - if (To == DefaultT && !(From == DefaultT)) - return make_error<ImportError>(); - return To; - // FIXME: This should be the final code. - //return Importer.Import(From); + return Importer.Import(From); + } + + // Import an Optional<T> by importing the contained T, if any. + template<typename T> + Expected<Optional<T>> import(Optional<T> From) { + if (!From) + return Optional<T>(); + return import(*From); } template <class T> @@ -283,18 +254,16 @@ namespace clang { LLVM_NODISCARD bool GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun, FromDeclT *FromD, Args &&... args) { - // FIXME: This code is needed later. - //if (Importer.getImportDeclErrorIfAny(FromD)) { - // ToD = nullptr; - // return true; // Already imported but with error. - //} + if (Importer.getImportDeclErrorIfAny(FromD)) { + ToD = nullptr; + return true; // Already imported but with error. + } ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD)); if (ToD) return true; // Already imported. ToD = CreateFun(std::forward<Args>(args)...); // Keep track of imported Decls. - Importer.MapImported(FromD, ToD); - Importer.AddToLookupTable(ToD); + Importer.RegisterImportedDecl(FromD, ToD); InitializeImportedDecl(FromD, ToD); return false; // A new Decl is created. } @@ -302,14 +271,31 @@ namespace clang { void InitializeImportedDecl(Decl *FromD, Decl *ToD) { ToD->IdentifierNamespace = FromD->IdentifierNamespace; if (FromD->hasAttrs()) - for (const Attr *FromAttr : FromD->getAttrs()) - ToD->addAttr(Importer.Import(FromAttr)); + for (const Attr *FromAttr : FromD->getAttrs()) { + // FIXME: Return of the error here is not possible until store of + // import errors is implemented. + auto ToAttrOrErr = import(FromAttr); + if (ToAttrOrErr) + ToD->addAttr(*ToAttrOrErr); + else + llvm::consumeError(ToAttrOrErr.takeError()); + } if (FromD->isUsed()) ToD->setIsUsed(); if (FromD->isImplicit()) ToD->setImplicit(); } + // Check if we have found an existing definition. Returns with that + // definition if yes, otherwise returns null. + Decl *FindAndMapDefinition(FunctionDecl *D, FunctionDecl *FoundFunction) { + const FunctionDecl *Definition = nullptr; + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody(Definition)) + return Importer.MapImported(D, const_cast<FunctionDecl *>(Definition)); + return nullptr; + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} @@ -412,8 +398,6 @@ namespace clang { Error ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); - Expected<TemplateParameterList *> ImportTemplateParameterList( - TemplateParameterList *Params); Error ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl<TemplateArgument> &ToArgs); @@ -435,9 +419,16 @@ namespace clang { Expected<FunctionTemplateAndArgsTy> ImportFunctionTemplateWithTemplateArgsFromSpecialization( FunctionDecl *FromFD); + Error ImportTemplateParameterLists(const DeclaratorDecl *FromD, + DeclaratorDecl *ToD); Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); + Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD); + + template <typename T> + bool hasSameVisibilityContext(T *Found, T *From); + bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); @@ -548,6 +539,7 @@ namespace clang { // Importing expressions ExpectedStmt VisitExpr(Expr *E); ExpectedStmt VisitVAArgExpr(VAArgExpr *E); + ExpectedStmt VisitChooseExpr(ChooseExpr *E); ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E); ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E); ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E); @@ -649,15 +641,6 @@ namespace clang { FunctionDecl *FromFD); }; -// FIXME: Temporary until every import returns Expected. -template <> -Expected<TemplateName> ASTNodeImporter::import(const TemplateName &From) { - TemplateName To = Importer.Import(From); - if (To.isNull() && !From.isNull()) - return make_error<ImportError>(); - return To; -} - template <typename InContainerTy> Error ASTNodeImporter::ImportTemplateArgumentListInfo( SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, @@ -1649,16 +1632,32 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { auto ToDCOrErr = Importer.ImportContext(FromDC); return ToDCOrErr.takeError(); } + + // We use strict error handling in case of records and enums, but not + // with e.g. namespaces. + // + // FIXME Clients of the ASTImporter should be able to choose an + // appropriate error handling strategy for their needs. For instance, + // they may not want to mark an entire namespace as erroneous merely + // because there is an ODR error with two typedefs. As another example, + // the client may allow EnumConstantDecls with same names but with + // different values in two distinct translation units. + bool AccumulateChildErrors = isa<TagDecl>(FromDC); + + Error ChildErrors = Error::success(); llvm::SmallVector<Decl *, 8> ImportedDecls; for (auto *From : FromDC->decls()) { ExpectedDecl ImportedOrErr = import(From); - if (!ImportedOrErr) - // Ignore the error, continue with next Decl. - // FIXME: Handle this case somehow better. - consumeError(ImportedOrErr.takeError()); + if (!ImportedOrErr) { + if (AccumulateChildErrors) + ChildErrors = + joinErrors(std::move(ChildErrors), ImportedOrErr.takeError()); + else + consumeError(ImportedOrErr.takeError()); + } } - return Error::success(); + return ChildErrors; } Error ASTNodeImporter::ImportDeclContext( @@ -1698,29 +1697,50 @@ Error ASTNodeImporter::ImportImplicitMethods( static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To, ASTImporter &Importer) { if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) { - Decl *ToTypedef = Importer.Import(FromTypedef); - if (!ToTypedef) - return make_error<ImportError>(); - To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToTypedef)); - // FIXME: This should be the final code. - //if (Expected<Decl *> ToTypedefOrErr = Importer.Import(FromTypedef)) - // To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr)); - //else - // return ToTypedefOrErr.takeError(); + if (ExpectedDecl ToTypedefOrErr = Importer.Import(FromTypedef)) + To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr)); + else + return ToTypedefOrErr.takeError(); } return Error::success(); } Error ASTNodeImporter::ImportDefinition( RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) { + auto DefinitionCompleter = [To]() { + // There are cases in LLDB when we first import a class without its + // members. The class will have DefinitionData, but no members. Then, + // importDefinition is called from LLDB, which tries to get the members, so + // when we get here, the class already has the DefinitionData set, so we + // must unset the CompleteDefinition here to be able to complete again the + // definition. + To->setCompleteDefinition(false); + To->completeDefinition(); + }; + if (To->getDefinition() || To->isBeingDefined()) { - if (Kind == IDK_Everything) - return ImportDeclContext(From, /*ForceImport=*/true); + if (Kind == IDK_Everything || + // In case of lambdas, the class already has a definition ptr set, but + // the contained decls are not imported yet. Also, isBeingDefined was + // set in CXXRecordDecl::CreateLambda. We must import the contained + // decls here and finish the definition. + (To->isLambda() && shouldForceImportDeclContext(Kind))) { + Error Result = ImportDeclContext(From, /*ForceImport=*/true); + // Finish the definition of the lambda, set isBeingDefined to false. + if (To->isLambda()) + DefinitionCompleter(); + return Result; + } return Error::success(); } To->startDefinition(); + // Complete the definition even if error is returned. + // The RecordDecl may be already part of the AST so it is better to + // have it in complete state even if something is wrong with it. + auto DefinitionCompleterScopeExit = + llvm::make_scope_exit(DefinitionCompleter); if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) return Err; @@ -1798,6 +1818,9 @@ Error ASTNodeImporter::ImportDefinition( ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; + // Copy over the data stored in RecordDeclBits + ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions()); + SmallVector<CXXBaseSpecifier *, 4> Bases; for (const auto &Base1 : FromCXX->bases()) { ExpectedType TyOrErr = import(Base1.getType()); @@ -1842,7 +1865,6 @@ Error ASTNodeImporter::ImportDefinition( if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; - To->completeDefinition(); return Error::success(); } @@ -1903,40 +1925,6 @@ Error ASTNodeImporter::ImportDefinition( return Error::success(); } -// FIXME: Remove this, use `import` instead. -Expected<TemplateParameterList *> ASTNodeImporter::ImportTemplateParameterList( - TemplateParameterList *Params) { - SmallVector<NamedDecl *, 4> ToParams(Params->size()); - if (Error Err = ImportContainerChecked(*Params, ToParams)) - return std::move(Err); - - Expr *ToRequiresClause; - if (Expr *const R = Params->getRequiresClause()) { - if (Error Err = importInto(ToRequiresClause, R)) - return std::move(Err); - } else { - ToRequiresClause = nullptr; - } - - auto ToTemplateLocOrErr = import(Params->getTemplateLoc()); - if (!ToTemplateLocOrErr) - return ToTemplateLocOrErr.takeError(); - auto ToLAngleLocOrErr = import(Params->getLAngleLoc()); - if (!ToLAngleLocOrErr) - return ToLAngleLocOrErr.takeError(); - auto ToRAngleLocOrErr = import(Params->getRAngleLoc()); - if (!ToRAngleLocOrErr) - return ToRAngleLocOrErr.takeError(); - - return TemplateParameterList::Create( - Importer.getToContext(), - *ToTemplateLocOrErr, - *ToLAngleLocOrErr, - ToParams, - *ToRAngleLocOrErr, - ToRequiresClause); -} - Error ASTNodeImporter::ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl<TemplateArgument> &ToArgs) { @@ -2011,6 +1999,12 @@ bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, } bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { + // Eliminate a potential failure point where we attempt to re-import + // something we're trying to import while completing ToEnum. + if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum)) + if (auto *ToOriginEnum = dyn_cast<EnumDecl>(ToOrigin)) + ToEnum = ToOriginEnum; + StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); @@ -2303,7 +2297,8 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType()) return Importer.MapImported(D, FoundTypedef); } - // FIXME Handle redecl chain. + // FIXME Handle redecl chain. When you do that make consistent changes + // in ASTImporterLookupTable too. break; } @@ -2492,6 +2487,8 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { } if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) { + if (!hasSameVisibilityContext(FoundEnum, D)) + continue; if (IsStructuralMatch(D, FoundEnum)) return Importer.MapImported(D, FoundEnum); } @@ -2500,7 +2497,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { } if (!ConflictingDecls.empty()) { - Name = Importer.HandleNameConflict(Name, DC, IDNS, + Name = Importer.HandleNameConflict(SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (!Name) @@ -2548,26 +2545,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Decl::FOK_None; } - // If this record has a definition in the translation unit we're coming from, - // but this particular declaration is not that definition, import the - // definition and map to that. - TagDecl *Definition = D->getDefinition(); - if (Definition && Definition != D && - // Friend template declaration must be imported on its own. - !IsFriendTemplate && - // In contrast to a normal CXXRecordDecl, the implicit - // CXXRecordDecl of ClassTemplateSpecializationDecl is its redeclaration. - // The definition of the implicit CXXRecordDecl in this case is the - // ClassTemplateSpecializationDecl itself. Thus, we start with an extra - // condition in order to be able to import the implict Decl. - !D->isImplicit()) { - ExpectedDecl ImportedDefOrErr = import(Definition); - if (!ImportedDefOrErr) - return ImportedDefOrErr.takeError(); - - return Importer.MapImported(D, *ImportedDefOrErr); - } - // Import the major distinguishing characteristics of this record. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -2596,7 +2573,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { auto FoundDecls = Importer.findDeclsInToCtx(DC, SearchName); if (!FoundDecls.empty()) { - // We're going to have to compare D against potentially conflicting Decls, so complete it. + // We're going to have to compare D against potentially conflicting Decls, + // so complete it. if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition()) D->getASTContext().getExternalSource()->CompleteType(D); } @@ -2625,6 +2603,9 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (!IsStructuralMatch(D, FoundRecord, false)) continue; + if (!hasSameVisibilityContext(FoundRecord, D)) + continue; + if (IsStructuralMatch(D, FoundRecord)) { RecordDecl *FoundDef = FoundRecord->getDefinition(); if (D->isThisDeclarationADefinition() && FoundDef) { @@ -2651,7 +2632,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } // for if (!ConflictingDecls.empty() && SearchName) { - Name = Importer.HandleNameConflict(Name, DC, IDNS, + Name = Importer.HandleNameConflict(SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (!Name) @@ -2848,6 +2829,22 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { return ToEnumerator; } +Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD, + DeclaratorDecl *ToD) { + unsigned int Num = FromD->getNumTemplateParameterLists(); + if (Num == 0) + return Error::success(); + SmallVector<TemplateParameterList *, 2> ToTPLists(Num); + for (unsigned int I = 0; I < Num; ++I) + if (Expected<TemplateParameterList *> ToTPListOrErr = + import(FromD->getTemplateParameterList(I))) + ToTPLists[I] = *ToTPListOrErr; + else + return ToTPListOrErr.takeError(); + ToD->setTemplateParameterListsInfo(Importer.ToContext, ToTPLists); + return Error::success(); +} + Error ASTNodeImporter::ImportTemplateInformation( FunctionDecl *FromFD, FunctionDecl *ToFD) { switch (FromFD->getTemplatedKind()) { @@ -2894,6 +2891,9 @@ Error ASTNodeImporter::ImportTemplateInformation( if (!POIOrErr) return POIOrErr.takeError(); + if (Error Err = ImportTemplateParameterLists(FromFD, ToFD)) + return Err; + TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); ToFD->setFunctionTemplateSpecialization( std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr, @@ -2945,6 +2945,30 @@ ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) { return FoundSpec; } +Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD, + FunctionDecl *ToFD) { + if (Stmt *FromBody = FromFD->getBody()) { + if (ExpectedStmt ToBodyOrErr = import(FromBody)) + ToFD->setBody(*ToBodyOrErr); + else + return ToBodyOrErr.takeError(); + } + return Error::success(); +} + +template <typename T> +bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) { + if (From->hasExternalFormalLinkage()) + return Found->hasExternalFormalLinkage(); + if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl()) + return false; + if (From->isInAnonymousNamespace()) + return Found->isInAnonymousNamespace(); + else + return !Found->isInAnonymousNamespace() && + !Found->hasExternalFormalLinkage(); +} + ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D); @@ -2968,7 +2992,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ToD) return ToD; - const FunctionDecl *FoundByLookup = nullptr; + FunctionDecl *FoundByLookup = nullptr; FunctionTemplateDecl *FromFT = D->getDescribedFunctionTemplate(); // If this is a function template specialization, then try to find the same @@ -2982,8 +3006,8 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (!FoundFunctionOrErr) return FoundFunctionOrErr.takeError(); if (FunctionDecl *FoundFunction = *FoundFunctionOrErr) { - if (D->doesThisDeclarationHaveABody() && FoundFunction->hasBody()) - return Importer.MapImported(D, FoundFunction); + if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) + return Def; FoundByLookup = FoundFunction; } } @@ -2998,33 +3022,27 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (auto *FoundFunction = dyn_cast<FunctionDecl>(FoundDecl)) { - if (FoundFunction->hasExternalFormalLinkage() && - D->hasExternalFormalLinkage()) { - if (IsStructuralMatch(D, FoundFunction)) { - const FunctionDecl *Definition = nullptr; - if (D->doesThisDeclarationHaveABody() && - FoundFunction->hasBody(Definition)) { - return Importer.MapImported( - D, const_cast<FunctionDecl *>(Definition)); - } - FoundByLookup = FoundFunction; - break; - } + if (!hasSameVisibilityContext(FoundFunction, D)) + continue; - // FIXME: Check for overloading more carefully, e.g., by boosting - // Sema::IsOverload out to the AST library. + if (IsStructuralMatch(D, FoundFunction)) { + if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) + return Def; + FoundByLookup = FoundFunction; + break; + } + // FIXME: Check for overloading more carefully, e.g., by boosting + // Sema::IsOverload out to the AST library. - // Function overloading is okay in C++. - if (Importer.getToContext().getLangOpts().CPlusPlus) - continue; + // Function overloading is okay in C++. + if (Importer.getToContext().getLangOpts().CPlusPlus) + continue; - // Complain about inconsistent function types. - Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) + // Complain about inconsistent function types. + Importer.ToDiag(Loc, diag::warn_odr_function_type_inconsistent) << Name << D->getType() << FoundFunction->getType(); - Importer.ToDiag(FoundFunction->getLocation(), - diag::note_odr_value_here) + Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here) << FoundFunction->getType(); - } } ConflictingDecls.push_back(FoundDecl); @@ -3039,6 +3057,25 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } + // We do not allow more than one in-class declaration of a function. This is + // because AST clients like VTableBuilder asserts on this. VTableBuilder + // assumes there is only one in-class declaration. Building a redecl + // chain would result in more than one in-class declaration for + // overrides (even if they are part of the same redecl chain inside the + // derived class.) + if (FoundByLookup) { + if (isa<CXXMethodDecl>(FoundByLookup)) { + if (D->getLexicalDeclContext() == D->getDeclContext()) { + if (!D->doesThisDeclarationHaveABody()) + return Importer.MapImported(D, FoundByLookup); + else { + // Let's continue and build up the redecl chain in this case. + // FIXME Merge the functions into one decl. + } + } + } + } + DeclarationNameInfo NameInfo(Name, Loc); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo)) @@ -3086,36 +3123,71 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { + Expr *ExplicitExpr = nullptr; + if (FromConstructor->getExplicitSpecifier().getExpr()) { + auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr()); + if (!Imp) + return Imp.takeError(); + std::tie(ExplicitExpr) = *Imp; + } if (GetImportedOrCreateDecl<CXXConstructorDecl>( - ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), - ToInnerLocStart, NameInfo, T, TInfo, - FromConstructor->isExplicit(), - D->isInlineSpecified(), D->isImplicit(), D->isConstexpr())) + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + ToInnerLocStart, NameInfo, T, TInfo, + ExplicitSpecifier( + ExplicitExpr, + FromConstructor->getExplicitSpecifier().getKind()), + D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind())) return ToFunction; - } else if (isa<CXXDestructorDecl>(D)) { + } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) { + + auto Imp = + importSeq(const_cast<FunctionDecl *>(FromDtor->getOperatorDelete()), + FromDtor->getOperatorDeleteThisArg()); + + if (!Imp) + return Imp.takeError(); + + FunctionDecl *ToOperatorDelete; + Expr *ToThisArg; + std::tie(ToOperatorDelete, ToThisArg) = *Imp; + if (GetImportedOrCreateDecl<CXXDestructorDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit())) return ToFunction; + + CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction); + + ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg); } else if (CXXConversionDecl *FromConversion = dyn_cast<CXXConversionDecl>(D)) { + Expr *ExplicitExpr = nullptr; + if (FromConversion->getExplicitSpecifier().getExpr()) { + auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr()); + if (!Imp) + return Imp.takeError(); + std::tie(ExplicitExpr) = *Imp; + } if (GetImportedOrCreateDecl<CXXConversionDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), - FromConversion->isExplicit(), D->isConstexpr(), SourceLocation())) + ExplicitSpecifier(ExplicitExpr, + FromConversion->getExplicitSpecifier().getKind()), + D->getConstexprKind(), SourceLocation())) return ToFunction; } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) { if (GetImportedOrCreateDecl<CXXMethodDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), - Method->isInlineSpecified(), D->isConstexpr(), SourceLocation())) + Method->isInlineSpecified(), D->getConstexprKind(), + SourceLocation())) return ToFunction; } else { - if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC, - ToInnerLocStart, NameInfo, T, TInfo, - D->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->isConstexpr())) + if (GetImportedOrCreateDecl( + ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, + NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), + D->hasWrittenPrototype(), D->getConstexprKind())) return ToFunction; } @@ -3124,6 +3196,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { auto *Recent = const_cast<FunctionDecl *>( FoundByLookup->getMostRecentDecl()); ToFunction->setPreviousDecl(Recent); + // FIXME Probably we should merge exception specifications. E.g. In the + // "To" context the existing function may have exception specification with + // noexcept-unevaluated, while the newly imported function may have an + // evaluated noexcept. A call to adjustExceptionSpec() on the imported + // decl and its redeclarations may be required. } // Import Ctor initializers. @@ -3184,12 +3261,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } if (D->doesThisDeclarationHaveABody()) { - if (Stmt *FromBody = D->getBody()) { - if (ExpectedStmt ToBodyOrErr = import(FromBody)) - ToFunction->setBody(*ToBodyOrErr); - else - return ToBodyOrErr.takeError(); - } + Error Err = ImportFunctionDeclBody(D, ToFunction); + + if (Err) + return std::move(Err); } // FIXME: Other bits to merge? @@ -3292,7 +3367,7 @@ ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { } // FIXME: Why is this case not handled with calling HandleNameConflict? - Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); @@ -3363,7 +3438,7 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { continue; // FIXME: Why is this case not handled with calling HandleNameConflict? - Importer.ToDiag(Loc, diag::err_odr_field_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); @@ -3394,9 +3469,6 @@ ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { // FIXME here we leak `NamedChain` which is allocated before return ToIndirectField; - for (const auto *Attr : D->attrs()) - ToIndirectField->addAttr(Importer.Import(Attr)); - ToIndirectField->setAccess(D->getAccess()); ToIndirectField->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIndirectField); @@ -3451,7 +3523,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists); auto **FromTPLists = D->getTrailingObjects<TemplateParameterList *>(); for (unsigned I = 0; I < D->NumTPLists; I++) { - if (auto ListOrErr = ImportTemplateParameterList(FromTPLists[I])) + if (auto ListOrErr = import(FromTPLists[I])) ToTPLists[I] = *ListOrErr; else return ListOrErr.takeError(); @@ -3497,7 +3569,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { return FoundIvar; } - Importer.ToDiag(Loc, diag::err_odr_ivar_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_ivar_type_inconsistent) << Name << D->getType() << FoundIvar->getType(); Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here) << FoundIvar->getType(); @@ -3564,58 +3636,56 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { continue; if (auto *FoundVar = dyn_cast<VarDecl>(FoundDecl)) { - // We have found a variable that we may need to merge with. Check it. - if (FoundVar->hasExternalFormalLinkage() && - D->hasExternalFormalLinkage()) { - if (Importer.IsStructurallyEquivalent(D->getType(), - FoundVar->getType())) { - - // The VarDecl in the "From" context has a definition, but in the - // "To" context we already have a definition. - VarDecl *FoundDef = FoundVar->getDefinition(); - if (D->isThisDeclarationADefinition() && FoundDef) - // FIXME Check for ODR error if the two definitions have - // different initializers? - return Importer.MapImported(D, FoundDef); - - // The VarDecl in the "From" context has an initializer, but in the - // "To" context we already have an initializer. - const VarDecl *FoundDInit = nullptr; - if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit)) - // FIXME Diagnose ODR error if the two initializers are different? - return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit)); + if (!hasSameVisibilityContext(FoundVar, D)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundVar->getType())) { + + // The VarDecl in the "From" context has a definition, but in the + // "To" context we already have a definition. + VarDecl *FoundDef = FoundVar->getDefinition(); + if (D->isThisDeclarationADefinition() && FoundDef) + // FIXME Check for ODR error if the two definitions have + // different initializers? + return Importer.MapImported(D, FoundDef); + + // The VarDecl in the "From" context has an initializer, but in the + // "To" context we already have an initializer. + const VarDecl *FoundDInit = nullptr; + if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit)) + // FIXME Diagnose ODR error if the two initializers are different? + return Importer.MapImported(D, const_cast<VarDecl*>(FoundDInit)); + + FoundByLookup = FoundVar; + break; + } + + const ArrayType *FoundArray + = Importer.getToContext().getAsArrayType(FoundVar->getType()); + const ArrayType *TArray + = Importer.getToContext().getAsArrayType(D->getType()); + if (FoundArray && TArray) { + if (isa<IncompleteArrayType>(FoundArray) && + isa<ConstantArrayType>(TArray)) { + // Import the type. + if (auto TyOrErr = import(D->getType())) + FoundVar->setType(*TyOrErr); + else + return TyOrErr.takeError(); FoundByLookup = FoundVar; break; + } else if (isa<IncompleteArrayType>(TArray) && + isa<ConstantArrayType>(FoundArray)) { + FoundByLookup = FoundVar; + break; } - - const ArrayType *FoundArray - = Importer.getToContext().getAsArrayType(FoundVar->getType()); - const ArrayType *TArray - = Importer.getToContext().getAsArrayType(D->getType()); - if (FoundArray && TArray) { - if (isa<IncompleteArrayType>(FoundArray) && - isa<ConstantArrayType>(TArray)) { - // Import the type. - if (auto TyOrErr = import(D->getType())) - FoundVar->setType(*TyOrErr); - else - return TyOrErr.takeError(); - - FoundByLookup = FoundVar; - break; - } else if (isa<IncompleteArrayType>(TArray) && - isa<ConstantArrayType>(FoundArray)) { - FoundByLookup = FoundVar; - break; - } - } - - Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent) - << Name << D->getType() << FoundVar->getType(); - Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) - << FoundVar->getType(); } + + Importer.ToDiag(Loc, diag::warn_odr_variable_type_inconsistent) + << Name << D->getType() << FoundVar->getType(); + Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) + << FoundVar->getType(); } ConflictingDecls.push_back(FoundDecl); @@ -3777,7 +3847,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check return types. if (!Importer.IsStructurallyEquivalent(D->getReturnType(), FoundMethod->getReturnType())) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_result_type_inconsistent) << D->isInstanceMethod() << Name << D->getReturnType() << FoundMethod->getReturnType(); Importer.ToDiag(FoundMethod->getLocation(), @@ -3789,7 +3859,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check the number of parameters. if (D->param_size() != FoundMethod->param_size()) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_num_params_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_num_params_inconsistent) << D->isInstanceMethod() << Name << D->param_size() << FoundMethod->param_size(); Importer.ToDiag(FoundMethod->getLocation(), @@ -3806,7 +3876,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { if (!Importer.IsStructurallyEquivalent((*P)->getType(), (*FoundP)->getType())) { Importer.FromDiag((*P)->getLocation(), - diag::err_odr_objc_method_param_type_inconsistent) + diag::warn_odr_objc_method_param_type_inconsistent) << D->isInstanceMethod() << Name << (*P)->getType() << (*FoundP)->getType(); Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here) @@ -3819,7 +3889,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Check variadic/non-variadic. // Check the number of parameters. if (D->isVariadic() != FoundMethod->isVariadic()) { - Importer.ToDiag(Loc, diag::err_odr_objc_method_variadic_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_method_variadic_inconsistent) << D->isInstanceMethod() << Name; Importer.ToDiag(FoundMethod->getLocation(), diag::note_odr_objc_method_here) @@ -4364,7 +4434,7 @@ Error ASTNodeImporter::ImportDefinition( if ((bool)FromSuper != (bool)ToSuper || (FromSuper && !declaresSameEntity(FromSuper, ToSuper))) { Importer.ToDiag(To->getLocation(), - diag::err_odr_objc_superclass_inconsistent) + diag::warn_odr_objc_superclass_inconsistent) << To->getDeclName(); if (ToSuper) Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass) @@ -4633,7 +4703,7 @@ ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { !declaresSameEntity(Super->getCanonicalDecl(), Impl->getSuperClass()))) { Importer.ToDiag(Impl->getLocation(), - diag::err_odr_objc_superclass_inconsistent) + diag::warn_odr_objc_superclass_inconsistent) << Iface->getDeclName(); // FIXME: It would be nice to have the location of the superclass // below. @@ -4681,7 +4751,7 @@ ExpectedDecl ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { - Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) + Importer.ToDiag(Loc, diag::warn_odr_objc_property_type_inconsistent) << Name << D->getType() << FoundProp->getType(); Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here) << FoundProp->getType(); @@ -4788,7 +4858,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { // vs. @dynamic). if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { Importer.ToDiag(ToImpl->getLocation(), - diag::err_odr_objc_property_impl_kind_inconsistent) + diag::warn_odr_objc_property_impl_kind_inconsistent) << Property->getDeclName() << (ToImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); @@ -4804,7 +4874,7 @@ ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && Ivar != ToImpl->getPropertyIvarDecl()) { Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), - diag::err_odr_objc_synthesize_ivar_inconsistent) + diag::warn_odr_objc_synthesize_ivar_inconsistent) << Property->getDeclName() << ToImpl->getPropertyIvarDecl()->getDeclName() << Ivar->getDeclName(); @@ -4888,8 +4958,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return LocationOrErr.takeError(); // Import template parameters. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -4905,31 +4974,20 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return ToD; } -// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if +// Returns the definition for a (forward) declaration of a TemplateDecl, if // it has any definition in the redecl chain. -static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) { - CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); +template <typename T> static auto getTemplateDefinition(T *D) -> T * { + assert(D->getTemplatedDecl() && "Should be called on templates only"); + auto *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); if (!ToTemplatedDef) return nullptr; - ClassTemplateDecl *TemplateWithDef = - ToTemplatedDef->getDescribedClassTemplate(); - return TemplateWithDef; + auto *TemplateWithDef = ToTemplatedDef->getDescribedTemplate(); + return cast_or_null<T>(TemplateWithDef); } ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None; - // If this template has a definition in the translation unit we're coming - // from, but this particular declaration is not that definition, import the - // definition and map to that. - ClassTemplateDecl *Definition = getDefinition(D); - if (Definition && Definition != D && !IsFriend) { - if (ExpectedDecl ImportedDefOrErr = import(Definition)) - return Importer.MapImported(D, *ImportedDefOrErr); - else - return ImportedDefOrErr.takeError(); - } - // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -4956,7 +5014,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (FoundTemplate) { if (IsStructuralMatch(D, FoundTemplate)) { - ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate); + ClassTemplateDecl *TemplateWithDef = + getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) { return Importer.MapImported(D, TemplateWithDef); } @@ -4986,8 +5045,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { return std::move(Err); // Create the class template declaration itself. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -5019,6 +5077,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // and this time the lookup finds the previous fwd friend class template. // In this case we must set up the previous decl for the templated decl. if (!ToTemplated->getPreviousDecl()) { + assert(FoundByLookup->getTemplatedDecl() && + "Found decl must have its templated decl set"); CXXRecordDecl *PrevTemplated = FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); if (ToTemplated != PrevTemplated) @@ -5041,17 +5101,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { - // If this record has a definition in the translation unit we're coming from, - // but this particular declaration is not that definition, import the - // definition and map to that. - TagDecl *Definition = D->getDefinition(); - if (Definition && Definition != D) { - if (ExpectedDecl ImportedDefOrErr = import(Definition)) - return Importer.MapImported(D, *ImportedDefOrErr); - else - return ImportedDefOrErr.takeError(); - } - ClassTemplateDecl *ClassTemplate; if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate())) return std::move(Err); @@ -5069,154 +5118,146 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Try to find an existing specialization with these template arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *D2 = nullptr; + ClassTemplateSpecializationDecl *PrevDecl = nullptr; ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(D); if (PartialSpec) - D2 = ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); + PrevDecl = + ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); else - D2 = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); - ClassTemplateSpecializationDecl * const PrevDecl = D2; - RecordDecl *FoundDef = D2 ? D2->getDefinition() : nullptr; - if (FoundDef) { - if (!D->isCompleteDefinition()) { - // The "From" translation unit only had a forward declaration; call it - // the same declaration. - // TODO Handle the redecl chain properly! - return Importer.MapImported(D, FoundDef); - } - - if (IsStructuralMatch(D, FoundDef)) { + PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); + + if (PrevDecl) { + if (IsStructuralMatch(D, PrevDecl)) { + if (D->isThisDeclarationADefinition() && PrevDecl->getDefinition()) { + Importer.MapImported(D, PrevDecl->getDefinition()); + // Import those default field initializers which have been + // instantiated in the "From" context, but not in the "To" context. + for (auto *FromField : D->fields()) { + auto ToOrErr = import(FromField); + if (!ToOrErr) + return ToOrErr.takeError(); + } - Importer.MapImported(D, FoundDef); + // Import those methods which have been instantiated in the + // "From" context, but not in the "To" context. + for (CXXMethodDecl *FromM : D->methods()) { + auto ToOrErr = import(FromM); + if (!ToOrErr) + return ToOrErr.takeError(); + } - // Import those those default field initializers which have been - // instantiated in the "From" context, but not in the "To" context. - for (auto *FromField : D->fields()) { - auto ToOrErr = import(FromField); - if (!ToOrErr) - // FIXME: return the error? - consumeError(ToOrErr.takeError()); + // TODO Import instantiated default arguments. + // TODO Import instantiated exception specifications. + // + // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint + // what else could be fused during an AST merge. + return PrevDecl; } + } else { // ODR violation. + // FIXME HandleNameConflict + return make_error<ImportError>(ImportError::NameConflict); + } + } - // Import those methods which have been instantiated in the - // "From" context, but not in the "To" context. - for (CXXMethodDecl *FromM : D->methods()) { - auto ToOrErr = import(FromM); - if (!ToOrErr) - // FIXME: return the error? - consumeError(ToOrErr.takeError()); - } + // Import the location of this declaration. + ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); + if (!BeginLocOrErr) + return BeginLocOrErr.takeError(); + ExpectedSLoc IdLocOrErr = import(D->getLocation()); + if (!IdLocOrErr) + return IdLocOrErr.takeError(); - // TODO Import instantiated default arguments. - // TODO Import instantiated exception specifications. - // - // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint what - // else could be fused during an AST merge. + // Create the specialization. + ClassTemplateSpecializationDecl *D2 = nullptr; + if (PartialSpec) { + // Import TemplateArgumentListInfo. + TemplateArgumentListInfo ToTAInfo; + const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); + if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) + return std::move(Err); - return FoundDef; - } - } else { // We either couldn't find any previous specialization in the "To" - // context, or we found one but without definition. Let's create a - // new specialization and register that at the class template. + QualType CanonInjType; + if (Error Err = importInto( + CanonInjType, PartialSpec->getInjectedSpecializationType())) + return std::move(Err); + CanonInjType = CanonInjType.getCanonicalType(); + + auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); + if (!ToTPListOrErr) + return ToTPListOrErr.takeError(); + + if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( + D2, D, Importer.getToContext(), D->getTagKind(), DC, + *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, + llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), + ToTAInfo, CanonInjType, + cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) + return D2; - // Import the location of this declaration. - ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); - if (!BeginLocOrErr) - return BeginLocOrErr.takeError(); - ExpectedSLoc IdLocOrErr = import(D->getLocation()); - if (!IdLocOrErr) - return IdLocOrErr.takeError(); - - if (PartialSpec) { - // Import TemplateArgumentListInfo. - TemplateArgumentListInfo ToTAInfo; - const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); - if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) - return std::move(Err); + // Update InsertPos, because preceding import calls may have invalidated + // it by adding new specializations. + if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) + // Add this partial specialization to the class template. + ClassTemplate->AddPartialSpecialization( + cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); - QualType CanonInjType; - if (Error Err = importInto( - CanonInjType, PartialSpec->getInjectedSpecializationType())) - return std::move(Err); - CanonInjType = CanonInjType.getCanonicalType(); + } else { // Not a partial specialization. + if (GetImportedOrCreateDecl( + D2, D, Importer.getToContext(), D->getTagKind(), DC, + *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, + PrevDecl)) + return D2; - auto ToTPListOrErr = ImportTemplateParameterList( - PartialSpec->getTemplateParameters()); - if (!ToTPListOrErr) - return ToTPListOrErr.takeError(); + // Update InsertPos, because preceding import calls may have invalidated + // it by adding new specializations. + if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos)) + // Add this specialization to the class template. + ClassTemplate->AddSpecialization(D2, InsertPos); + } - if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( - D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, - llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), - ToTAInfo, CanonInjType, - cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) - return D2; + D2->setSpecializationKind(D->getSpecializationKind()); - // Update InsertPos, because preceding import calls may have invalidated - // it by adding new specializations. - if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) - // Add this partial specialization to the class template. - ClassTemplate->AddPartialSpecialization( - cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); + // Set the context of this specialization/instantiation. + D2->setLexicalDeclContext(LexicalDC); - } else { // Not a partial specialization. - if (GetImportedOrCreateDecl( - D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, - PrevDecl)) - return D2; + // Add to the DC only if it was an explicit specialization/instantiation. + if (D2->isExplicitInstantiationOrSpecialization()) { + LexicalDC->addDeclInternal(D2); + } - // Update InsertPos, because preceding import calls may have invalidated - // it by adding new specializations. - if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos)) - // Add this specialization to the class template. - ClassTemplate->AddSpecialization(D2, InsertPos); - } + // Import the qualifier, if any. + if (auto LocOrErr = import(D->getQualifierLoc())) + D2->setQualifierInfo(*LocOrErr); + else + return LocOrErr.takeError(); - D2->setSpecializationKind(D->getSpecializationKind()); + if (auto *TSI = D->getTypeAsWritten()) { + if (auto TInfoOrErr = import(TSI)) + D2->setTypeAsWritten(*TInfoOrErr); + else + return TInfoOrErr.takeError(); - // Import the qualifier, if any. - if (auto LocOrErr = import(D->getQualifierLoc())) - D2->setQualifierInfo(*LocOrErr); + if (auto LocOrErr = import(D->getTemplateKeywordLoc())) + D2->setTemplateKeywordLoc(*LocOrErr); else return LocOrErr.takeError(); - if (auto *TSI = D->getTypeAsWritten()) { - if (auto TInfoOrErr = import(TSI)) - D2->setTypeAsWritten(*TInfoOrErr); - else - return TInfoOrErr.takeError(); - - if (auto LocOrErr = import(D->getTemplateKeywordLoc())) - D2->setTemplateKeywordLoc(*LocOrErr); - else - return LocOrErr.takeError(); - - if (auto LocOrErr = import(D->getExternLoc())) - D2->setExternLoc(*LocOrErr); - else - return LocOrErr.takeError(); - } - - if (D->getPointOfInstantiation().isValid()) { - if (auto POIOrErr = import(D->getPointOfInstantiation())) - D2->setPointOfInstantiation(*POIOrErr); - else - return POIOrErr.takeError(); - } + if (auto LocOrErr = import(D->getExternLoc())) + D2->setExternLoc(*LocOrErr); + else + return LocOrErr.takeError(); + } - D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); + if (D->getPointOfInstantiation().isValid()) { + if (auto POIOrErr = import(D->getPointOfInstantiation())) + D2->setPointOfInstantiation(*POIOrErr); + else + return POIOrErr.takeError(); + } - // Set the context of this specialization/instantiation. - D2->setLexicalDeclContext(LexicalDC); + D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); - // Add to the DC only if it was an explicit specialization/instantiation. - if (D2->isExplicitInstantiationOrSpecialization()) { - LexicalDC->addDeclInternal(D2); - } - } if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2)) return std::move(Err); @@ -5296,8 +5337,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { return std::move(Err); // Create the variable template declaration itself. - auto TemplateParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); @@ -5333,7 +5373,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( return ImportedDefOrErr.takeError(); } - VarTemplateDecl *VarTemplate; + VarTemplateDecl *VarTemplate = nullptr; if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate())) return std::move(Err); @@ -5402,8 +5442,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( *FromTAArgsAsWritten, ArgInfos)) return std::move(Err); - auto ToTPListOrErr = ImportTemplateParameterList( - FromPartial->getTemplateParameters()); + auto ToTPListOrErr = import(FromPartial->getTemplateParameters()); if (!ToTPListOrErr) return ToTPListOrErr.takeError(); @@ -5481,32 +5520,37 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ToD) return ToD; + const FunctionTemplateDecl *FoundByLookup = nullptr; + // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. + // FIXME Split this into a separate function. if (!LexicalDC->isFunctionOrMethod()) { - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (auto *FoundFunction = - dyn_cast<FunctionTemplateDecl>(FoundDecl)) { - if (FoundFunction->hasExternalFormalLinkage() && + if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) { + if (FoundTemplate->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { - if (IsStructuralMatch(D, FoundFunction)) { - Importer.MapImported(D, FoundFunction); - // FIXME: Actually try to merge the body and other attributes. - return FoundFunction; + if (IsStructuralMatch(D, FoundTemplate)) { + FunctionTemplateDecl *TemplateWithDef = + getTemplateDefinition(FoundTemplate); + if (D->isThisDeclarationADefinition() && TemplateWithDef) { + return Importer.MapImported(D, TemplateWithDef); + } + FoundByLookup = FoundTemplate; + break; } + // TODO: handle conflicting names } } - // TODO: handle conflicting names } } - auto ParamsOrErr = ImportTemplateParameterList( - D->getTemplateParameters()); + auto ParamsOrErr = import(D->getTemplateParameters()); if (!ParamsOrErr) return ParamsOrErr.takeError(); @@ -5520,10 +5564,25 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { return ToFunc; TemplatedFD->setDescribedFunctionTemplate(ToFunc); + ToFunc->setAccess(D->getAccess()); ToFunc->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(ToFunc); + + if (FoundByLookup) { + auto *Recent = + const_cast<FunctionTemplateDecl *>(FoundByLookup->getMostRecentDecl()); + if (!TemplatedFD->getPreviousDecl()) { + assert(FoundByLookup->getTemplatedDecl() && + "Found decl must have its templated decl set"); + auto *PrevTemplated = + FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); + if (TemplatedFD != PrevTemplated) + TemplatedFD->setPreviousDecl(PrevTemplated); + } + ToFunc->setPreviousDecl(Recent); + } + return ToFunc; } @@ -5539,6 +5598,8 @@ ExpectedStmt ASTNodeImporter::VisitStmt(Stmt *S) { ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { + if (Importer.returnWithErrorInTest()) + return make_error<ImportError>(ImportError::UnsupportedConstruct); SmallVector<IdentifierInfo *, 4> Names; for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) { IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I)); @@ -5578,12 +5639,17 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { return InputOrErr.takeError(); } - SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs()); + SmallVector<Expr *, 4> Exprs(S->getNumOutputs() + S->getNumInputs() + + S->getNumLabels()); if (Error Err = ImportContainerChecked(S->outputs(), Exprs)) return std::move(Err); + if (Error Err = + ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs())) + return std::move(Err); + if (Error Err = ImportArrayChecked( - S->inputs(), Exprs.begin() + S->getNumOutputs())) + S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs())) return std::move(Err); ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc()); @@ -5609,6 +5675,7 @@ ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { *AsmStrOrErr, S->getNumClobbers(), Clobbers.data(), + S->getNumLabels(), *RParenLocOrErr); } @@ -6079,6 +6146,33 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { E->isMicrosoftABI()); } +ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) { + auto Imp = importSeq(E->getCond(), E->getLHS(), E->getRHS(), + E->getBuiltinLoc(), E->getRParenLoc(), E->getType()); + if (!Imp) + return Imp.takeError(); + + Expr *ToCond; + Expr *ToLHS; + Expr *ToRHS; + SourceLocation ToBuiltinLoc, ToRParenLoc; + QualType ToType; + std::tie(ToCond, ToLHS, ToRHS, ToBuiltinLoc, ToRParenLoc, ToType) = *Imp; + + ExprValueKind VK = E->getValueKind(); + ExprObjectKind OK = E->getObjectKind(); + + bool TypeDependent = ToCond->isTypeDependent(); + bool ValueDependent = ToCond->isValueDependent(); + + // The value of CondIsTrue only matters if the value is not + // condition-dependent. + bool CondIsTrue = !E->isConditionDependent() && E->isConditionTrue(); + + return new (Importer.getToContext()) + ChooseExpr(ToBuiltinLoc, ToCond, ToLHS, ToRHS, ToType, VK, OK, + ToRParenLoc, CondIsTrue, TypeDependent, ValueDependent); +} ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { ExpectedType TypeOrErr = import(E->getType()); @@ -6141,7 +6235,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { auto *ToE = DeclRefExpr::Create( Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl, E->refersToEnclosingVariableOrCapture(), ToLocation, ToType, - E->getValueKind(), ToFoundD, ToResInfo); + E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse()); if (E->hadMultipleCandidates()) ToE->setHadMultipleCandidates(true); return ToE; @@ -6327,6 +6421,13 @@ ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { Expr *ToSubExpr; std::tie(ToSubExpr) = *Imp; + // TODO : Handle APValue::ValueKind that require importing. + APValue::ValueKind Kind = E->getResultAPValueKind(); + if (Kind == APValue::Int || Kind == APValue::Float || + Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || + Kind == APValue::ComplexInt) + return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, + E->getAPValueResult()); return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); } @@ -6763,8 +6864,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { if (!ToParamOrErr) return ToParamOrErr.takeError(); + auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); + if (!UsedContextOrErr) + return UsedContextOrErr.takeError(); + return CXXDefaultArgExpr::Create( - Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr); + Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr); } ExpectedStmt @@ -6898,7 +7003,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) { FunctionDecl *ToOperatorNew, *ToOperatorDelete; SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange; - Expr *ToArraySize, *ToInitializer; + Optional<Expr *> ToArraySize; + Expr *ToInitializer; QualType ToType; TypeSourceInfo *ToAllocatedTypeSourceInfo; std::tie( @@ -7051,15 +7157,20 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { DeclarationNameInfo ToMemberNameInfo(ToName, ToLoc); + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - // FIXME: handle template arguments - return make_error<ImportError>(ImportError::UnsupportedConstruct); + if (Error Err = + ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) + return std::move(Err); + ResInfo = &ToTAInfo; } - return MemberExpr::Create( - Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, - ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl, - ToMemberNameInfo, nullptr, ToType, E->getValueKind(), E->getObjectKind()); + return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(), + ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, + ToMemberDecl, ToFoundDecl, ToMemberNameInfo, + ResInfo, ToType, E->getValueKind(), + E->getObjectKind(), E->isNonOdrUse()); } ExpectedStmt @@ -7334,23 +7445,10 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { return ToClassOrErr.takeError(); CXXRecordDecl *ToClass = *ToClassOrErr; - // NOTE: lambda classes are created with BeingDefined flag set up. - // It means that ImportDefinition doesn't work for them and we should fill it - // manually. - if (ToClass->isBeingDefined()) { - for (auto FromField : FromClass->fields()) { - auto ToFieldOrErr = import(FromField); - if (!ToFieldOrErr) - return ToFieldOrErr.takeError(); - } - } - auto ToCallOpOrErr = import(E->getCallOperator()); if (!ToCallOpOrErr) return ToCallOpOrErr.takeError(); - ToClass->completeDefinition(); - SmallVector<LambdaCapture, 8> ToCaptures; ToCaptures.reserve(E->capture_size()); for (const auto &FromCapture : E->captures()) { @@ -7486,8 +7584,12 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { if (!ToFieldOrErr) return ToFieldOrErr.takeError(); + auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); + if (!UsedContextOrErr) + return UsedContextOrErr.takeError(); + return CXXDefaultInitExpr::Create( - Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr); + Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr, *UsedContextOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { @@ -7613,24 +7715,22 @@ void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, - ASTImporterLookupTable *LookupTable) - : LookupTable(LookupTable), ToContext(ToContext), FromContext(FromContext), + std::shared_ptr<ASTImporterSharedState> SharedState) + : SharedState(SharedState), ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), Minimal(MinimalImport) { + // Create a default state without the lookup table: LLDB case. + if (!SharedState) { + this->SharedState = std::make_shared<ASTImporterSharedState>(); + } + ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); } ASTImporter::~ASTImporter() = default; -Expected<QualType> ASTImporter::Import_New(QualType FromT) { - QualType ToT = Import(FromT); - if (ToT.isNull() && !FromT.isNull()) - return make_error<ImportError>(); - return ToT; -} - Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) { assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) && "Try to get field index for non-field."); @@ -7663,28 +7763,46 @@ ASTImporter::findDeclsInToCtx(DeclContext *DC, DeclarationName Name) { // then the enum constant 'A' and the variable 'A' violates ODR. // We can diagnose this only if we search in the redecl context. DeclContext *ReDC = DC->getRedeclContext(); - if (LookupTable) { + if (SharedState->getLookupTable()) { ASTImporterLookupTable::LookupResult LookupResult = - LookupTable->lookup(ReDC, Name); + SharedState->getLookupTable()->lookup(ReDC, Name); return FoundDeclsTy(LookupResult.begin(), LookupResult.end()); } else { - // FIXME Can we remove this kind of lookup? - // Or lldb really needs this C/C++ lookup? - FoundDeclsTy Result; - ReDC->localUncachedLookup(Name, Result); + DeclContext::lookup_result NoloadLookupResult = ReDC->noload_lookup(Name); + FoundDeclsTy Result(NoloadLookupResult.begin(), NoloadLookupResult.end()); + // We must search by the slow case of localUncachedLookup because that is + // working even if there is no LookupPtr for the DC. We could use + // DC::buildLookup() to create the LookupPtr, but that would load external + // decls again, we must avoid that case. + // Also, even if we had the LookupPtr, we must find Decls which are not + // in the LookupPtr, so we need the slow case. + // These cases are handled in ASTImporterLookupTable, but we cannot use + // that with LLDB since that traverses through the AST which initiates the + // load of external decls again via DC::decls(). And again, we must avoid + // loading external decls during the import. + if (Result.empty()) + ReDC->localUncachedLookup(Name, Result); return Result; } } void ASTImporter::AddToLookupTable(Decl *ToD) { - if (LookupTable) - if (auto *ToND = dyn_cast<NamedDecl>(ToD)) - LookupTable->add(ToND); + SharedState->addDeclToLookup(ToD); +} + +Expected<Decl *> ASTImporter::ImportImpl(Decl *FromD) { + // Import the decl using ASTNodeImporter. + ASTNodeImporter Importer(*this); + return Importer.Visit(FromD); +} + +void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) { + MapImported(FromD, ToD); } -QualType ASTImporter::Import(QualType FromT) { +Expected<QualType> ASTImporter::Import(QualType FromT) { if (FromT.isNull()) - return {}; + return QualType{}; const Type *FromTy = FromT.getTypePtr(); @@ -7697,10 +7815,8 @@ QualType ASTImporter::Import(QualType FromT) { // Import the type ASTNodeImporter Importer(*this); ExpectedType ToTOrErr = Importer.Visit(FromTy); - if (!ToTOrErr) { - llvm::consumeError(ToTOrErr.takeError()); - return {}; - } + if (!ToTOrErr) + return ToTOrErr.takeError(); // Record the imported type. ImportedTypes[FromTy] = (*ToTOrErr).getTypePtr(); @@ -7708,33 +7824,29 @@ QualType ASTImporter::Import(QualType FromT) { return ToContext.getQualifiedType(*ToTOrErr, FromT.getLocalQualifiers()); } -Expected<TypeSourceInfo *> ASTImporter::Import_New(TypeSourceInfo *FromTSI) { - TypeSourceInfo *ToTSI = Import(FromTSI); - if (!ToTSI && FromTSI) - return llvm::make_error<ImportError>(); - return ToTSI; -} -TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { +Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) { if (!FromTSI) return FromTSI; // FIXME: For now we just create a "trivial" type source info based // on the type and a single location. Implement a real version of this. - QualType T = Import(FromTSI->getType()); - if (T.isNull()) - return nullptr; + ExpectedType TOrErr = Import(FromTSI->getType()); + if (!TOrErr) + return TOrErr.takeError(); + ExpectedSLoc BeginLocOrErr = Import(FromTSI->getTypeLoc().getBeginLoc()); + if (!BeginLocOrErr) + return BeginLocOrErr.takeError(); - return ToContext.getTrivialTypeSourceInfo( - T, Import(FromTSI->getTypeLoc().getBeginLoc())); + return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr); } -Expected<Attr *> ASTImporter::Import_New(const Attr *FromAttr) { - return Import(FromAttr); -} -Attr *ASTImporter::Import(const Attr *FromAttr) { +Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) { Attr *ToAttr = FromAttr->clone(ToContext); - // NOTE: Import of SourceRange may fail. - ToAttr->setRange(Import(FromAttr->getRange())); + if (auto ToRangeOrErr = Import(FromAttr->getRange())) + ToAttr->setRange(*ToRangeOrErr); + else + return ToRangeOrErr.takeError(); + return ToAttr; } @@ -7746,53 +7858,147 @@ Decl *ASTImporter::GetAlreadyImportedOrNull(const Decl *FromD) const { return nullptr; } -Expected<Decl *> ASTImporter::Import_New(Decl *FromD) { - Decl *ToD = Import(FromD); - if (!ToD && FromD) - return llvm::make_error<ImportError>(); - return ToD; +TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) { + auto FromDPos = ImportedFromDecls.find(ToD); + if (FromDPos == ImportedFromDecls.end()) + return nullptr; + return FromDPos->second->getTranslationUnitDecl(); } -Decl *ASTImporter::Import(Decl *FromD) { + +Expected<Decl *> ASTImporter::Import(Decl *FromD) { if (!FromD) return nullptr; - ASTNodeImporter Importer(*this); + // Push FromD to the stack, and remove that when we return. + ImportPath.push(FromD); + auto ImportPathBuilder = + llvm::make_scope_exit([this]() { ImportPath.pop(); }); + + // Check whether there was a previous failed import. + // If yes return the existing error. + if (auto Error = getImportDeclErrorIfAny(FromD)) + return make_error<ImportError>(*Error); // Check whether we've already imported this declaration. Decl *ToD = GetAlreadyImportedOrNull(FromD); if (ToD) { + // Already imported (possibly from another TU) and with an error. + if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { + setImportDeclError(FromD, *Error); + return make_error<ImportError>(*Error); + } + // If FromD has some updated flags after last import, apply it updateFlags(FromD, ToD); + // If we encounter a cycle during an import then we save the relevant part + // of the import path associated to the Decl. + if (ImportPath.hasCycleAtBack()) + SavedImportPaths[FromD].push_back(ImportPath.copyCycleAtBack()); return ToD; } - // Import the type. - ExpectedDecl ToDOrErr = Importer.Visit(FromD); + // Import the declaration. + ExpectedDecl ToDOrErr = ImportImpl(FromD); if (!ToDOrErr) { - llvm::consumeError(ToDOrErr.takeError()); - return nullptr; + // Failed to import. + + auto Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) { + // Import failed after the object was created. + // Remove all references to it. + auto *ToD = Pos->second; + ImportedDecls.erase(Pos); + + // ImportedDecls and ImportedFromDecls are not symmetric. It may happen + // (e.g. with namespaces) that several decls from the 'from' context are + // mapped to the same decl in the 'to' context. If we removed entries + // from the LookupTable here then we may end up removing them multiple + // times. + + // The Lookuptable contains decls only which are in the 'to' context. + // Remove from the Lookuptable only if it is *imported* into the 'to' + // context (and do not remove it if it was added during the initial + // traverse of the 'to' context). + auto PosF = ImportedFromDecls.find(ToD); + if (PosF != ImportedFromDecls.end()) { + SharedState->removeDeclFromLookup(ToD); + ImportedFromDecls.erase(PosF); + } + + // FIXME: AST may contain remaining references to the failed object. + // However, the ImportDeclErrors in the shared state contains all the + // failed objects together with their error. + } + + // Error encountered for the first time. + // After takeError the error is not usable any more in ToDOrErr. + // Get a copy of the error object (any more simple solution for this?). + ImportError ErrOut; + handleAllErrors(ToDOrErr.takeError(), + [&ErrOut](const ImportError &E) { ErrOut = E; }); + setImportDeclError(FromD, ErrOut); + // Set the error for the mapped to Decl, which is in the "to" context. + if (Pos != ImportedDecls.end()) + SharedState->setImportDeclError(Pos->second, ErrOut); + + // Set the error for all nodes which have been created before we + // recognized the error. + for (const auto &Path : SavedImportPaths[FromD]) + for (Decl *FromDi : Path) { + setImportDeclError(FromDi, ErrOut); + //FIXME Should we remove these Decls from ImportedDecls? + // Set the error for the mapped to Decl, which is in the "to" context. + auto Ii = ImportedDecls.find(FromDi); + if (Ii != ImportedDecls.end()) + SharedState->setImportDeclError(Ii->second, ErrOut); + // FIXME Should we remove these Decls from the LookupTable, + // and from ImportedFromDecls? + } + SavedImportPaths[FromD].clear(); + + // Do not return ToDOrErr, error was taken out of it. + return make_error<ImportError>(ErrOut); } + ToD = *ToDOrErr; - // Once the decl is connected to the existing declarations, i.e. when the - // redecl chain is properly set then we populate the lookup again. - // This way the primary context will be able to find all decls. - AddToLookupTable(ToD); + // FIXME: Handle the "already imported with error" case. We can get here + // nullptr only if GetImportedOrCreateDecl returned nullptr (after a + // previously failed create was requested). + // Later GetImportedOrCreateDecl can be updated to return the error. + if (!ToD) { + auto Err = getImportDeclErrorIfAny(FromD); + assert(Err); + return make_error<ImportError>(*Err); + } + + // We could import from the current TU without error. But previously we + // already had imported a Decl as `ToD` from another TU (with another + // ASTImporter object) and with an error. + if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { + setImportDeclError(FromD, *Error); + return make_error<ImportError>(*Error); + } + + // Make sure that ImportImpl registered the imported decl. + assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?"); // Notify subclasses. Imported(FromD, ToD); updateFlags(FromD, ToD); - return ToD; + SavedImportPaths[FromD].clear(); + return ToDOrErr; } Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) { if (!FromDC) return FromDC; - auto *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); - if (!ToDC) - return nullptr; + ExpectedDecl ToDCOrErr = Import(cast<Decl>(FromDC)); + if (!ToDCOrErr) + return ToDCOrErr.takeError(); + auto *ToDC = cast<DeclContext>(*ToDCOrErr); // When we're using a record/enum/Objective-C class/protocol as a context, we // need it to have a definition. @@ -7845,30 +8051,18 @@ Expected<DeclContext *> ASTImporter::ImportContext(DeclContext *FromDC) { return ToDC; } -Expected<Expr *> ASTImporter::Import_New(Expr *FromE) { - Expr *ToE = Import(FromE); - if (!ToE && FromE) - return llvm::make_error<ImportError>(); - return ToE; -} -Expr *ASTImporter::Import(Expr *FromE) { - if (!FromE) - return nullptr; - - return cast_or_null<Expr>(Import(cast<Stmt>(FromE))); +Expected<Expr *> ASTImporter::Import(Expr *FromE) { + if (ExpectedStmt ToSOrErr = Import(cast_or_null<Stmt>(FromE))) + return cast_or_null<Expr>(*ToSOrErr); + else + return ToSOrErr.takeError(); } -Expected<Stmt *> ASTImporter::Import_New(Stmt *FromS) { - Stmt *ToS = Import(FromS); - if (!ToS && FromS) - return llvm::make_error<ImportError>(); - return ToS; -} -Stmt *ASTImporter::Import(Stmt *FromS) { +Expected<Stmt *> ASTImporter::Import(Stmt *FromS) { if (!FromS) return nullptr; - // Check whether we've already imported this declaration. + // Check whether we've already imported this statement. llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS); if (Pos != ImportedStmts.end()) return Pos->second; @@ -7876,10 +8070,8 @@ Stmt *ASTImporter::Import(Stmt *FromS) { // Import the statement. ASTNodeImporter Importer(*this); ExpectedStmt ToSOrErr = Importer.Visit(FromS); - if (!ToSOrErr) { - llvm::consumeError(ToSOrErr.takeError()); - return nullptr; - } + if (!ToSOrErr) + return ToSOrErr; if (auto *ToE = dyn_cast<Expr>(*ToSOrErr)) { auto *FromE = cast<Expr>(FromS); @@ -7894,77 +8086,68 @@ Stmt *ASTImporter::Import(Stmt *FromS) { FromE->containsUnexpandedParameterPack()); } - // Record the imported declaration. + // Record the imported statement object. ImportedStmts[FromS] = *ToSOrErr; - return *ToSOrErr; + return ToSOrErr; } Expected<NestedNameSpecifier *> -ASTImporter::Import_New(NestedNameSpecifier *FromNNS) { - NestedNameSpecifier *ToNNS = Import(FromNNS); - if (!ToNNS && FromNNS) - return llvm::make_error<ImportError>(); - return ToNNS; -} -NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { +ASTImporter::Import(NestedNameSpecifier *FromNNS) { if (!FromNNS) return nullptr; - NestedNameSpecifier *prefix = Import(FromNNS->getPrefix()); + NestedNameSpecifier *Prefix = nullptr; + if (Error Err = importInto(Prefix, FromNNS->getPrefix())) + return std::move(Err); switch (FromNNS->getKind()) { case NestedNameSpecifier::Identifier: - if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) { - return NestedNameSpecifier::Create(ToContext, prefix, II); - } - return nullptr; + assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); + return NestedNameSpecifier::Create(ToContext, Prefix, + Import(FromNNS->getAsIdentifier())); case NestedNameSpecifier::Namespace: - if (auto *NS = - cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NS); - } - return nullptr; + if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { + return NestedNameSpecifier::Create(ToContext, Prefix, + cast<NamespaceDecl>(*NSOrErr)); + } else + return NSOrErr.takeError(); case NestedNameSpecifier::NamespaceAlias: - if (auto *NSAD = - cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) { - return NestedNameSpecifier::Create(ToContext, prefix, NSAD); - } - return nullptr; + if (ExpectedDecl NSADOrErr = Import(FromNNS->getAsNamespaceAlias())) + return NestedNameSpecifier::Create(ToContext, Prefix, + cast<NamespaceAliasDecl>(*NSADOrErr)); + else + return NSADOrErr.takeError(); case NestedNameSpecifier::Global: return NestedNameSpecifier::GlobalSpecifier(ToContext); case NestedNameSpecifier::Super: - if (auto *RD = - cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) { - return NestedNameSpecifier::SuperSpecifier(ToContext, RD); - } - return nullptr; + if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) + return NestedNameSpecifier::SuperSpecifier(ToContext, + cast<CXXRecordDecl>(*RDOrErr)); + else + return RDOrErr.takeError(); case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - QualType T = Import(QualType(FromNNS->getAsType(), 0u)); - if (!T.isNull()) { - bool bTemplate = FromNNS->getKind() == - NestedNameSpecifier::TypeSpecWithTemplate; - return NestedNameSpecifier::Create(ToContext, prefix, - bTemplate, T.getTypePtr()); - } + case NestedNameSpecifier::TypeSpecWithTemplate: + if (Expected<QualType> TyOrErr = + Import(QualType(FromNNS->getAsType(), 0u))) { + bool TSTemplate = + FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate; + return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate, + TyOrErr->getTypePtr()); + } else { + return TyOrErr.takeError(); } - return nullptr; } llvm_unreachable("Invalid nested name specifier kind"); } Expected<NestedNameSpecifierLoc> -ASTImporter::Import_New(NestedNameSpecifierLoc FromNNS) { - NestedNameSpecifierLoc ToNNS = Import(FromNNS); - return ToNNS; -} -NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { +ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // Copied from NestedNameSpecifier mostly. SmallVector<NestedNameSpecifierLoc , 8> NestedNames; NestedNameSpecifierLoc NNS = FromNNS; @@ -7980,54 +8163,62 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); - NestedNameSpecifier *Spec = Import(NNS.getNestedNameSpecifier()); - if (!Spec) - return NestedNameSpecifierLoc(); + NestedNameSpecifier *Spec = nullptr; + if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) + return std::move(Err); NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); + + SourceLocation ToLocalBeginLoc, ToLocalEndLoc; + if (Kind != NestedNameSpecifier::Super) { + if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) + return std::move(Err); + + if (Kind != NestedNameSpecifier::Global) + if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) + return std::move(Err); + } + switch (Kind) { case NestedNameSpecifier::Identifier: - Builder.Extend(getToContext(), - Spec->getAsIdentifier(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, + ToLocalEndLoc); break; case NestedNameSpecifier::Namespace: - Builder.Extend(getToContext(), - Spec->getAsNamespace(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, + ToLocalEndLoc); break; case NestedNameSpecifier::NamespaceAlias: - Builder.Extend(getToContext(), - Spec->getAsNamespaceAlias(), - Import(NNS.getLocalBeginLoc()), - Import(NNS.getLocalEndLoc())); + Builder.Extend(getToContext(), Spec->getAsNamespaceAlias(), + ToLocalBeginLoc, ToLocalEndLoc); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { + SourceLocation ToTLoc; + if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) + return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( - QualType(Spec->getAsType(), 0)); - Builder.Extend(getToContext(), - Import(NNS.getLocalBeginLoc()), - TSI->getTypeLoc(), - Import(NNS.getLocalEndLoc())); + QualType(Spec->getAsType(), 0), ToTLoc); + Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(), + ToLocalEndLoc); break; } case NestedNameSpecifier::Global: - Builder.MakeGlobal(getToContext(), Import(NNS.getLocalBeginLoc())); + Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; case NestedNameSpecifier::Super: { - SourceRange ToRange = Import(NNS.getSourceRange()); - Builder.MakeSuper(getToContext(), - Spec->getAsRecordDecl(), - ToRange.getBegin(), - ToRange.getEnd()); + auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); + if (!ToSourceRangeOrErr) + return ToSourceRangeOrErr.takeError(); + + Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), + ToSourceRangeOrErr->getBegin(), + ToSourceRangeOrErr->getEnd()); } } } @@ -8035,137 +8226,126 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { return Builder.getWithLocInContext(getToContext()); } -Expected<TemplateName> ASTImporter::Import_New(TemplateName From) { - TemplateName To = Import(From); - if (To.isNull() && !From.isNull()) - return llvm::make_error<ImportError>(); - return To; -} -TemplateName ASTImporter::Import(TemplateName From) { +Expected<TemplateName> ASTImporter::Import(TemplateName From) { switch (From.getKind()) { case TemplateName::Template: - if (auto *ToTemplate = - cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) - return TemplateName(ToTemplate); - - return {}; + if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) + return TemplateName(cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); UnresolvedSet<2> ToTemplates; for (auto *I : *FromStorage) { - if (auto *To = cast_or_null<NamedDecl>(Import(I))) - ToTemplates.addDecl(To); + if (auto ToOrErr = Import(I)) + ToTemplates.addDecl(cast<NamedDecl>(*ToOrErr)); else - return {}; + return ToOrErr.takeError(); } return ToContext.getOverloadedTemplateName(ToTemplates.begin(), ToTemplates.end()); } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *FromStorage = From.getAsAssumedTemplateName(); + auto DeclNameOrErr = Import(FromStorage->getDeclName()); + if (!DeclNameOrErr) + return DeclNameOrErr.takeError(); + return ToContext.getAssumedTemplateName(*DeclNameOrErr); + } + case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); - NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); - if (!Qualifier) - return {}; - - if (auto *ToTemplate = - cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) - return ToContext.getQualifiedTemplateName(Qualifier, - QTN->hasTemplateKeyword(), - ToTemplate); - - return {}; + auto QualifierOrErr = Import(QTN->getQualifier()); + if (!QualifierOrErr) + return QualifierOrErr.takeError(); + + if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) + return ToContext.getQualifiedTemplateName( + *QualifierOrErr, QTN->hasTemplateKeyword(), + cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); } case TemplateName::DependentTemplate: { DependentTemplateName *DTN = From.getAsDependentTemplateName(); - NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); - if (!Qualifier) - return {}; + auto QualifierOrErr = Import(DTN->getQualifier()); + if (!QualifierOrErr) + return QualifierOrErr.takeError(); if (DTN->isIdentifier()) { - return ToContext.getDependentTemplateName(Qualifier, + return ToContext.getDependentTemplateName(*QualifierOrErr, Import(DTN->getIdentifier())); } - return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); + return ToContext.getDependentTemplateName(*QualifierOrErr, + DTN->getOperator()); } case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = From.getAsSubstTemplateTemplateParm(); - auto *param = - cast_or_null<TemplateTemplateParmDecl>(Import(subst->getParameter())); - if (!param) - return {}; + SubstTemplateTemplateParmStorage *Subst = + From.getAsSubstTemplateTemplateParm(); + ExpectedDecl ParamOrErr = Import(Subst->getParameter()); + if (!ParamOrErr) + return ParamOrErr.takeError(); - TemplateName replacement = Import(subst->getReplacement()); - if (replacement.isNull()) - return {}; + auto ReplacementOrErr = Import(Subst->getReplacement()); + if (!ReplacementOrErr) + return ReplacementOrErr.takeError(); - return ToContext.getSubstTemplateTemplateParm(param, replacement); + return ToContext.getSubstTemplateTemplateParm( + cast<TemplateTemplateParmDecl>(*ParamOrErr), *ReplacementOrErr); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = From.getAsSubstTemplateTemplateParmPack(); - auto *Param = - cast_or_null<TemplateTemplateParmDecl>( - Import(SubstPack->getParameterPack())); - if (!Param) - return {}; + ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack()); + if (!ParamOrErr) + return ParamOrErr.takeError(); ASTNodeImporter Importer(*this); - Expected<TemplateArgument> ArgPack - = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); - if (!ArgPack) { - llvm::consumeError(ArgPack.takeError()); - return {}; - } + auto ArgPackOrErr = + Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + if (!ArgPackOrErr) + return ArgPackOrErr.takeError(); - return ToContext.getSubstTemplateTemplateParmPack(Param, *ArgPack); + return ToContext.getSubstTemplateTemplateParmPack( + cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr); } } llvm_unreachable("Invalid template name kind"); } -Expected<SourceLocation> ASTImporter::Import_New(SourceLocation FromLoc) { - SourceLocation ToLoc = Import(FromLoc); - if (ToLoc.isInvalid() && !FromLoc.isInvalid()) - return llvm::make_error<ImportError>(); - return ToLoc; -} -SourceLocation ASTImporter::Import(SourceLocation FromLoc) { +Expected<SourceLocation> ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) - return {}; + return SourceLocation{}; SourceManager &FromSM = FromContext.getSourceManager(); + bool IsBuiltin = FromSM.isWrittenInBuiltinFile(FromLoc); std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); - FileID ToFileID = Import(Decomposed.first); - if (ToFileID.isInvalid()) - return {}; + Expected<FileID> ToFileIDOrErr = Import(Decomposed.first, IsBuiltin); + if (!ToFileIDOrErr) + return ToFileIDOrErr.takeError(); SourceManager &ToSM = ToContext.getSourceManager(); - return ToSM.getComposedLoc(ToFileID, Decomposed.second); + return ToSM.getComposedLoc(*ToFileIDOrErr, Decomposed.second); } -Expected<SourceRange> ASTImporter::Import_New(SourceRange FromRange) { - SourceRange ToRange = Import(FromRange); - return ToRange; -} -SourceRange ASTImporter::Import(SourceRange FromRange) { - return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd())); -} +Expected<SourceRange> ASTImporter::Import(SourceRange FromRange) { + SourceLocation ToBegin, ToEnd; + if (Error Err = importInto(ToBegin, FromRange.getBegin())) + return std::move(Err); + if (Error Err = importInto(ToEnd, FromRange.getEnd())) + return std::move(Err); -Expected<FileID> ASTImporter::Import_New(FileID FromID) { - FileID ToID = Import(FromID); - if (ToID.isInvalid() && FromID.isValid()) - return llvm::make_error<ImportError>(); - return ToID; + return SourceRange(ToBegin, ToEnd); } -FileID ASTImporter::Import(FileID FromID) { + +Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) { llvm::DenseMap<FileID, FileID>::iterator Pos = ImportedFileIDs.find(FromID); if (Pos != ImportedFileIDs.end()) return Pos->second; @@ -8178,38 +8358,58 @@ FileID ASTImporter::Import(FileID FromID) { FileID ToID; if (FromSLoc.isExpansion()) { const SrcMgr::ExpansionInfo &FromEx = FromSLoc.getExpansion(); - SourceLocation ToSpLoc = Import(FromEx.getSpellingLoc()); - SourceLocation ToExLocS = Import(FromEx.getExpansionLocStart()); + ExpectedSLoc ToSpLoc = Import(FromEx.getSpellingLoc()); + if (!ToSpLoc) + return ToSpLoc.takeError(); + ExpectedSLoc ToExLocS = Import(FromEx.getExpansionLocStart()); + if (!ToExLocS) + return ToExLocS.takeError(); unsigned TokenLen = FromSM.getFileIDSize(FromID); SourceLocation MLoc; if (FromEx.isMacroArgExpansion()) { - MLoc = ToSM.createMacroArgExpansionLoc(ToSpLoc, ToExLocS, TokenLen); + MLoc = ToSM.createMacroArgExpansionLoc(*ToSpLoc, *ToExLocS, TokenLen); } else { - SourceLocation ToExLocE = Import(FromEx.getExpansionLocEnd()); - MLoc = ToSM.createExpansionLoc(ToSpLoc, ToExLocS, ToExLocE, TokenLen, - FromEx.isExpansionTokenRange()); + if (ExpectedSLoc ToExLocE = Import(FromEx.getExpansionLocEnd())) + MLoc = ToSM.createExpansionLoc(*ToSpLoc, *ToExLocS, *ToExLocE, TokenLen, + FromEx.isExpansionTokenRange()); + else + return ToExLocE.takeError(); } ToID = ToSM.getFileID(MLoc); } else { - // Include location of this file. - SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); - const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { - // FIXME: We probably want to use getVirtualFile(), so we don't hit the - // disk again - // FIXME: We definitely want to re-use the existing MemoryBuffer, rather - // than mmap the files several times. - const FileEntry *Entry = - ToFileManager.getFile(Cache->OrigEntry->getName()); - if (!Entry) - return {}; - ToID = ToSM.createFileID(Entry, ToIncludeLoc, - FromSLoc.getFile().getFileCharacteristic()); - } else { + + if (!IsBuiltin) { + // Include location of this file. + ExpectedSLoc ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + if (!ToIncludeLoc) + return ToIncludeLoc.takeError(); + + if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = + ToFileManager.getFile(Cache->OrigEntry->getName()); + // FIXME: The filename may be a virtual name that does probably not + // point to a valid file and we get no Entry here. In this case try with + // the memory buffer below. + if (Entry) + ToID = ToSM.createFileID(Entry, *ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } + } + + if (ToID.isInvalid() || IsBuiltin) { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = - Cache->getBuffer(FromContext.getDiagnostics(), FromSM); + bool Invalid = true; + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer( + FromContext.getDiagnostics(), FromSM, SourceLocation{}, &Invalid); + if (!FromBuf || Invalid) + // FIXME: Use a new error kind? + return llvm::make_error<ImportError>(ImportError::Unknown); + std::unique_ptr<llvm::MemoryBuffer> ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); @@ -8218,186 +8418,187 @@ FileID ASTImporter::Import(FileID FromID) { } } + assert(ToID.isValid() && "Unexpected invalid fileID was created."); + ImportedFileIDs[FromID] = ToID; return ToID; } -Expected<CXXCtorInitializer *> -ASTImporter::Import_New(CXXCtorInitializer *From) { - CXXCtorInitializer *To = Import(From); - if (!To && From) - return llvm::make_error<ImportError>(); - return To; -} -CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { - Expr *ToExpr = Import(From->getInit()); - if (!ToExpr && From->getInit()) - return nullptr; +Expected<CXXCtorInitializer *> ASTImporter::Import(CXXCtorInitializer *From) { + ExpectedExpr ToExprOrErr = Import(From->getInit()); + if (!ToExprOrErr) + return ToExprOrErr.takeError(); + + auto LParenLocOrErr = Import(From->getLParenLoc()); + if (!LParenLocOrErr) + return LParenLocOrErr.takeError(); + + auto RParenLocOrErr = Import(From->getRParenLoc()); + if (!RParenLocOrErr) + return RParenLocOrErr.takeError(); if (From->isBaseInitializer()) { - TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); - if (!ToTInfo && From->getTypeSourceInfo()) - return nullptr; + auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); + if (!ToTInfoOrErr) + return ToTInfoOrErr.takeError(); + + SourceLocation EllipsisLoc; + if (From->isPackExpansion()) + if (Error Err = importInto(EllipsisLoc, From->getEllipsisLoc())) + return std::move(Err); return new (ToContext) CXXCtorInitializer( - ToContext, ToTInfo, From->isBaseVirtual(), Import(From->getLParenLoc()), - ToExpr, Import(From->getRParenLoc()), - From->isPackExpansion() ? Import(From->getEllipsisLoc()) - : SourceLocation()); + ToContext, *ToTInfoOrErr, From->isBaseVirtual(), *LParenLocOrErr, + *ToExprOrErr, *RParenLocOrErr, EllipsisLoc); } else if (From->isMemberInitializer()) { - auto *ToField = cast_or_null<FieldDecl>(Import(From->getMember())); - if (!ToField && From->getMember()) - return nullptr; + ExpectedDecl ToFieldOrErr = Import(From->getMember()); + if (!ToFieldOrErr) + return ToFieldOrErr.takeError(); + + auto MemberLocOrErr = Import(From->getMemberLocation()); + if (!MemberLocOrErr) + return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( - ToContext, ToField, Import(From->getMemberLocation()), - Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + ToContext, cast_or_null<FieldDecl>(*ToFieldOrErr), *MemberLocOrErr, + *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isIndirectMemberInitializer()) { - auto *ToIField = cast_or_null<IndirectFieldDecl>( - Import(From->getIndirectMember())); - if (!ToIField && From->getIndirectMember()) - return nullptr; + ExpectedDecl ToIFieldOrErr = Import(From->getIndirectMember()); + if (!ToIFieldOrErr) + return ToIFieldOrErr.takeError(); + + auto MemberLocOrErr = Import(From->getMemberLocation()); + if (!MemberLocOrErr) + return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( - ToContext, ToIField, Import(From->getMemberLocation()), - Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); + ToContext, cast_or_null<IndirectFieldDecl>(*ToIFieldOrErr), + *MemberLocOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isDelegatingInitializer()) { - TypeSourceInfo *ToTInfo = Import(From->getTypeSourceInfo()); - if (!ToTInfo && From->getTypeSourceInfo()) - return nullptr; + auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); + if (!ToTInfoOrErr) + return ToTInfoOrErr.takeError(); return new (ToContext) - CXXCtorInitializer(ToContext, ToTInfo, Import(From->getLParenLoc()), - ToExpr, Import(From->getRParenLoc())); + CXXCtorInitializer(ToContext, *ToTInfoOrErr, *LParenLocOrErr, + *ToExprOrErr, *RParenLocOrErr); } else { - return nullptr; + // FIXME: assert? + return make_error<ImportError>(); } } Expected<CXXBaseSpecifier *> -ASTImporter::Import_New(const CXXBaseSpecifier *From) { - CXXBaseSpecifier *To = Import(From); - if (!To && From) - return llvm::make_error<ImportError>(); - return To; -} -CXXBaseSpecifier *ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { +ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { auto Pos = ImportedCXXBaseSpecifiers.find(BaseSpec); if (Pos != ImportedCXXBaseSpecifiers.end()) return Pos->second; + Expected<SourceRange> ToSourceRange = Import(BaseSpec->getSourceRange()); + if (!ToSourceRange) + return ToSourceRange.takeError(); + Expected<TypeSourceInfo *> ToTSI = Import(BaseSpec->getTypeSourceInfo()); + if (!ToTSI) + return ToTSI.takeError(); + ExpectedSLoc ToEllipsisLoc = Import(BaseSpec->getEllipsisLoc()); + if (!ToEllipsisLoc) + return ToEllipsisLoc.takeError(); CXXBaseSpecifier *Imported = new (ToContext) CXXBaseSpecifier( - Import(BaseSpec->getSourceRange()), - BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(), - BaseSpec->getAccessSpecifierAsWritten(), - Import(BaseSpec->getTypeSourceInfo()), - Import(BaseSpec->getEllipsisLoc())); + *ToSourceRange, BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(), + BaseSpec->getAccessSpecifierAsWritten(), *ToTSI, *ToEllipsisLoc); ImportedCXXBaseSpecifiers[BaseSpec] = Imported; return Imported; } -Error ASTImporter::ImportDefinition_New(Decl *From) { - Decl *To = Import(From); - if (!To) - return llvm::make_error<ImportError>(); +Error ASTImporter::ImportDefinition(Decl *From) { + ExpectedDecl ToOrErr = Import(From); + if (!ToOrErr) + return ToOrErr.takeError(); + Decl *To = *ToOrErr; - if (auto *FromDC = cast<DeclContext>(From)) { - ASTNodeImporter Importer(*this); + auto *FromDC = cast<DeclContext>(From); + ASTNodeImporter Importer(*this); - if (auto *ToRecord = dyn_cast<RecordDecl>(To)) { - if (!ToRecord->getDefinition()) { - return Importer.ImportDefinition( - cast<RecordDecl>(FromDC), ToRecord, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToRecord = dyn_cast<RecordDecl>(To)) { + if (!ToRecord->getDefinition()) { + return Importer.ImportDefinition( + cast<RecordDecl>(FromDC), ToRecord, + ASTNodeImporter::IDK_Everything); } + } - if (auto *ToEnum = dyn_cast<EnumDecl>(To)) { - if (!ToEnum->getDefinition()) { - return Importer.ImportDefinition( - cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); - } + if (auto *ToEnum = dyn_cast<EnumDecl>(To)) { + if (!ToEnum->getDefinition()) { + return Importer.ImportDefinition( + cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); } + } - if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { - if (!ToIFace->getDefinition()) { - return Importer.ImportDefinition( - cast<ObjCInterfaceDecl>(FromDC), ToIFace, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { + if (!ToIFace->getDefinition()) { + return Importer.ImportDefinition( + cast<ObjCInterfaceDecl>(FromDC), ToIFace, + ASTNodeImporter::IDK_Everything); } + } - if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { - if (!ToProto->getDefinition()) { - return Importer.ImportDefinition( - cast<ObjCProtocolDecl>(FromDC), ToProto, - ASTNodeImporter::IDK_Everything); - } + if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { + if (!ToProto->getDefinition()) { + return Importer.ImportDefinition( + cast<ObjCProtocolDecl>(FromDC), ToProto, + ASTNodeImporter::IDK_Everything); } - - return Importer.ImportDeclContext(FromDC, true); } - return Error::success(); + return Importer.ImportDeclContext(FromDC, true); } -void ASTImporter::ImportDefinition(Decl *From) { - Error Err = ImportDefinition_New(From); - llvm::consumeError(std::move(Err)); -} - -Expected<DeclarationName> ASTImporter::Import_New(DeclarationName FromName) { - DeclarationName ToName = Import(FromName); - if (!ToName && FromName) - return llvm::make_error<ImportError>(); - return ToName; -} -DeclarationName ASTImporter::Import(DeclarationName FromName) { +Expected<DeclarationName> ASTImporter::Import(DeclarationName FromName) { if (!FromName) - return {}; + return DeclarationName{}; switch (FromName.getNameKind()) { case DeclarationName::Identifier: - return Import(FromName.getAsIdentifierInfo()); + return DeclarationName(Import(FromName.getAsIdentifierInfo())); case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: - return Import(FromName.getObjCSelector()); + if (auto ToSelOrErr = Import(FromName.getObjCSelector())) + return DeclarationName(*ToSelOrErr); + else + return ToSelOrErr.takeError(); case DeclarationName::CXXConstructorName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXConstructorName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXConstructorName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXDestructorName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXDestructorName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXDestructorName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXDeductionGuideName: { - auto *Template = cast_or_null<TemplateDecl>( - Import(FromName.getCXXDeductionGuideTemplate())); - if (!Template) - return {}; - return ToContext.DeclarationNames.getCXXDeductionGuideName(Template); + if (auto ToTemplateOrErr = Import(FromName.getCXXDeductionGuideTemplate())) + return ToContext.DeclarationNames.getCXXDeductionGuideName( + cast<TemplateDecl>(*ToTemplateOrErr)); + else + return ToTemplateOrErr.takeError(); } case DeclarationName::CXXConversionFunctionName: { - QualType T = Import(FromName.getCXXNameType()); - if (T.isNull()) - return {}; - - return ToContext.DeclarationNames.getCXXConversionFunctionName( - ToContext.getCanonicalType(T)); + if (auto ToTyOrErr = Import(FromName.getCXXNameType())) + return ToContext.DeclarationNames.getCXXConversionFunctionName( + ToContext.getCanonicalType(*ToTyOrErr)); + else + return ToTyOrErr.takeError(); } case DeclarationName::CXXOperatorName: @@ -8406,7 +8607,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { case DeclarationName::CXXLiteralOperatorName: return ToContext.DeclarationNames.getCXXLiteralOperatorName( - Import(FromName.getCXXLiteralIdentifier())); + Import(FromName.getCXXLiteralIdentifier())); case DeclarationName::CXXUsingDirective: // FIXME: STATICS! @@ -8428,15 +8629,9 @@ IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { return ToId; } -Expected<Selector> ASTImporter::Import_New(Selector FromSel) { - Selector ToSel = Import(FromSel); - if (ToSel.isNull() && !FromSel.isNull()) - return llvm::make_error<ImportError>(); - return ToSel; -} -Selector ASTImporter::Import(Selector FromSel) { +Expected<Selector> ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) - return {}; + return Selector{}; SmallVector<IdentifierInfo *, 4> Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); @@ -8496,15 +8691,42 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) { if (Pos != ImportedDecls.end()) return Pos->second; ImportedDecls[From] = To; + // This mapping should be maintained only in this function. Therefore do not + // check for additional consistency. + ImportedFromDecls[To] = From; + AddToLookupTable(To); return To; } +llvm::Optional<ImportError> +ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const { + auto Pos = ImportDeclErrors.find(FromD); + if (Pos != ImportDeclErrors.end()) + return Pos->second; + else + return Optional<ImportError>(); +} + +void ASTImporter::setImportDeclError(Decl *From, ImportError Error) { + auto InsertRes = ImportDeclErrors.insert({From, Error}); + (void)InsertRes; + // Either we set the error for the first time, or we already had set one and + // now we want to set the same error. + assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); +} + bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, bool Complain) { - llvm::DenseMap<const Type *, const Type *>::iterator Pos - = ImportedTypes.find(From.getTypePtr()); - if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) - return true; + llvm::DenseMap<const Type *, const Type *>::iterator Pos = + ImportedTypes.find(From.getTypePtr()); + if (Pos != ImportedTypes.end()) { + if (ExpectedType ToFromOrErr = Import(From)) { + if (ToContext.hasSameType(*ToFromOrErr, To)) + return true; + } else { + llvm::consumeError(ToFromOrErr.takeError()); + } + } StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, getStructuralEquivalenceKind(*this), false, diff --git a/lib/AST/ASTImporterLookupTable.cpp b/lib/AST/ASTImporterLookupTable.cpp index fbcd4f5cb3417..7390329d4ed8d 100644 --- a/lib/AST/ASTImporterLookupTable.cpp +++ b/lib/AST/ASTImporterLookupTable.cpp @@ -1,9 +1,8 @@ //===- ASTImporterLookupTable.cpp - ASTImporter specific lookup -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -27,17 +26,30 @@ struct Builder : RecursiveASTVisitor<Builder> { LT.add(D); return true; } + // In most cases the FriendDecl contains the declaration of the befriended + // class as a child node, so it is discovered during the recursive + // visitation. However, there are cases when the befriended class is not a + // child, thus it must be fetched explicitly from the FriendDecl, and only + // then can we add it to the lookup table. bool VisitFriendDecl(FriendDecl *D) { if (D->getFriendType()) { QualType Ty = D->getFriendType()->getType(); - // FIXME Can this be other than elaborated? - QualType NamedTy = cast<ElaboratedType>(Ty)->getNamedType(); - if (!NamedTy->isDependentType()) { - if (const auto *RTy = dyn_cast<RecordType>(NamedTy)) + if (isa<ElaboratedType>(Ty)) + Ty = cast<ElaboratedType>(Ty)->getNamedType(); + // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) + // always has that decl as child node. + // However, there are non-dependent cases which does not have the + // type as a child node. We have to dig up that type now. + if (!Ty->isDependentType()) { + if (const auto *RTy = dyn_cast<RecordType>(Ty)) LT.add(RTy->getAsCXXRecordDecl()); - else if (const auto *SpecTy = - dyn_cast<TemplateSpecializationType>(NamedTy)) { + else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty)) LT.add(SpecTy->getAsCXXRecordDecl()); + else if (isa<TypedefType>(Ty)) { + // We do not put friend typedefs to the lookup table because + // ASTImporter does not organize typedefs into redecl chains. + } else { + llvm_unreachable("Unhandled type of friend class"); } } } diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index d19b89bb95b48..912db3c130c51 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -1,9 +1,8 @@ //===- ASTStructuralEquivalence.cpp ---------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -74,6 +73,7 @@ #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -101,6 +101,59 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2); +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2); + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const DeclarationName Name1, + const DeclarationName Name2) { + if (Name1.getNameKind() != Name2.getNameKind()) + return false; + + switch (Name1.getNameKind()) { + + case DeclarationName::Identifier: + return IsStructurallyEquivalent(Name1.getAsIdentifierInfo(), + Name2.getAsIdentifierInfo()); + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + return IsStructurallyEquivalent(Context, Name1.getCXXNameType(), + Name2.getCXXNameType()); + + case DeclarationName::CXXDeductionGuideName: { + if (!IsStructurallyEquivalent( + Context, Name1.getCXXDeductionGuideTemplate()->getDeclName(), + Name2.getCXXDeductionGuideTemplate()->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, + Name1.getCXXDeductionGuideTemplate(), + Name2.getCXXDeductionGuideTemplate()); + } + + case DeclarationName::CXXOperatorName: + return Name1.getCXXOverloadedOperator() == Name2.getCXXOverloadedOperator(); + + case DeclarationName::CXXLiteralOperatorName: + return IsStructurallyEquivalent(Name1.getCXXLiteralIdentifier(), + Name2.getCXXLiteralIdentifier()); + + case DeclarationName::CXXUsingDirective: + return true; // FIXME When do we consider two using directives equal? + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return true; // FIXME + } + + llvm_unreachable("Unhandled kind of DeclarationName"); + return true; +} /// Determine structural equivalence of two expressions. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -108,7 +161,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!E1 || !E2) return E1 == E2; - // FIXME: Actually perform a structural comparison! + if (auto *DE1 = dyn_cast<DependentScopeDeclRefExpr>(E1)) { + auto *DE2 = dyn_cast<DependentScopeDeclRefExpr>(E2); + if (!DE2) + return false; + if (!IsStructurallyEquivalent(Context, DE1->getDeclName(), + DE2->getDeclName())) + return false; + return IsStructurallyEquivalent(Context, DE1->getQualifier(), + DE2->getQualifier()); + } else if (auto CastE1 = dyn_cast<ImplicitCastExpr>(E1)) { + auto *CastE2 = dyn_cast<ImplicitCastExpr>(E2); + if (!CastE2) + return false; + if (!IsStructurallyEquivalent(Context, CastE1->getType(), + CastE2->getType())) + return false; + return IsStructurallyEquivalent(Context, CastE1->getSubExpr(), + CastE2->getSubExpr()); + } + // FIXME: Handle other kind of expressions! return true; } @@ -181,6 +253,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return I1 == E1 && I2 == E2; } + case TemplateName::AssumedTemplate: { + AssumedTemplateStorage *TN1 = N1.getAsAssumedTemplateName(), + *TN2 = N1.getAsAssumedTemplateName(); + return TN1->getDeclName() == TN2->getDeclName(); + } + case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), *QN2 = N2.getAsQualifiedTemplateName(); @@ -297,6 +375,62 @@ static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence based on the ExtInfo of functions. This +/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling +/// conventions bits but must not compare some other bits. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FunctionType::ExtInfo EI1, + FunctionType::ExtInfo EI2) { + // Compatible functions must have compatible calling conventions. + if (EI1.getCC() != EI2.getCC()) + return false; + + // Regparm is part of the calling convention. + if (EI1.getHasRegParm() != EI2.getHasRegParm()) + return false; + if (EI1.getRegParm() != EI2.getRegParm()) + return false; + + if (EI1.getProducesResult() != EI2.getProducesResult()) + return false; + if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs()) + return false; + if (EI1.getNoCfCheck() != EI2.getNoCfCheck()) + return false; + + return true; +} + +/// Check the equivalence of exception specifications. +static bool IsEquivalentExceptionSpec(StructuralEquivalenceContext &Context, + const FunctionProtoType *Proto1, + const FunctionProtoType *Proto2) { + + auto Spec1 = Proto1->getExceptionSpecType(); + auto Spec2 = Proto2->getExceptionSpecType(); + + if (isUnresolvedExceptionSpec(Spec1) || isUnresolvedExceptionSpec(Spec2)) + return true; + + if (Spec1 != Spec2) + return false; + if (Spec1 == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (isComputedNoexcept(Spec1)) { + if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) + return false; + } + + return true; +} + /// Determine structural equivalence of two types. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, QualType T1, QualType T2) { @@ -503,7 +637,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + if (Proto1->getMethodQuals() != Proto2->getMethodQuals()) return false; // Check exceptions, this information is lost in canonical type. @@ -511,24 +645,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx)); const auto *OrigProto2 = cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx)); - auto Spec1 = OrigProto1->getExceptionSpecType(); - auto Spec2 = OrigProto2->getExceptionSpecType(); - - if (Spec1 != Spec2) + if (!IsEquivalentExceptionSpec(Context, OrigProto1, OrigProto2)) return false; - if (Spec1 == EST_Dynamic) { - if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I), - OrigProto2->getExceptionType(I))) - return false; - } - } else if (isComputedNoexcept(Spec1)) { - if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(), - OrigProto2->getNoexceptExpr())) - return false; - } // Fall through to check the bits common with FunctionNoProtoType. LLVM_FALLTHROUGH; @@ -540,7 +658,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), Function2->getReturnType())) return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) + if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(), + Function2->getExtInfo())) return false; break; } @@ -569,6 +688,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::MacroQualified: + if (!IsStructurallyEquivalent( + Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(), + cast<MacroQualifiedType>(T2)->getUnderlyingType())) + return false; + break; + case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), cast<TypedefType>(T2)->getDecl())) @@ -834,10 +960,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, IdentifierInfo *Name2 = Field2->getIdentifier(); if (!::IsStructurallyEquivalent(Name1, Name2)) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_field_name) << Field2->getDeclName(); @@ -850,10 +975,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -865,10 +989,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field1->isBitField() != Field2->isBitField()) { if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2( + Owner2->getLocation(), + Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); if (Field1->isBitField()) { Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) @@ -895,9 +1018,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Bits1 != Bits2) { if (Context.Complain) { Context.Diag2(Owner2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(Owner2); Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) << Field2->getDeclName() << Field2->getType() << Bits2; @@ -933,13 +1055,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) { auto *Constructor2 = cast<CXXConstructorDecl>(Method2); - if (Constructor1->isExplicit() != Constructor2->isExplicit()) + if (!Constructor1->getExplicitSpecifier().isEquivalent( + Constructor2->getExplicitSpecifier())) return false; } if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) { auto *Conversion2 = cast<CXXConversionDecl>(Method2); - if (Conversion1->isExplicit() != Conversion2->isExplicit()) + if (!Conversion1->getExplicitSpecifier().isEquivalent( + Conversion2->getExplicitSpecifier())) return false; if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(), Conversion2->getConversionType())) @@ -961,15 +1085,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence of two lambda classes. +static bool +IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context, + CXXRecordDecl *D1, CXXRecordDecl *D2) { + assert(D1->isLambda() && D2->isLambda() && + "Must be called on lambda classes"); + if (!IsStructurallyEquivalent(Context, D1->getLambdaCallOperator(), + D2->getLambdaCallOperator())) + return false; + + return true; +} + /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { if (D1->isUnion() != D2->isUnion()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); @@ -1044,9 +1179,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX); } + if (D1CXX->isLambda() != D2CXX->isLambda()) + return false; + if (D1CXX->isLambda()) { + if (!IsStructurallyEquivalentLambdas(Context, D1CXX, D2CXX)) + return false; + } + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) << D2CXX->getNumBases(); @@ -1065,7 +1209,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Base2->getType())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base) << Base2->getType() << Base2->getSourceRange(); @@ -1079,7 +1224,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Base1->isVirtual() != Base2->isVirtual()) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base) << Base2->isVirtual() << Base2->getSourceRange(); @@ -1092,15 +1238,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Check the friends for consistency. CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(), - Friend2End = D2CXX->friend_end(); + Friend2End = D2CXX->friend_end(); for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(), - Friend1End = D1CXX->friend_end(); + Friend1End = D1CXX->friend_end(); Friend1 != Friend1End; ++Friend1, ++Friend2) { if (Friend2 == Friend2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2CXX); + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); } @@ -1109,8 +1256,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2CXX); + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); } @@ -1120,8 +1269,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Friend2 != Friend2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); } @@ -1129,7 +1280,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } } else if (D1CXX->getNumBases() > 0) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -1149,9 +1302,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field2 == Field2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); @@ -1166,10 +1318,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Field2 != Field2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -1200,9 +1350,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (EC2 == EC2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) << EC1->getDeclName() << EC1->getInitVal().toString(10); @@ -1217,9 +1366,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); @@ -1232,10 +1380,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (EC2 != EC2End) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.ErrorOnTagTypeMismatch - ? diag::err_odr_tag_type_inconsistent - : diag::warn_odr_tag_type_inconsistent) + Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( + diag::err_odr_tag_type_inconsistent)) << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); @@ -1253,7 +1399,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Params1->size() != Params2->size()) { if (Context.Complain) { Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) + Context.getApplicableDiagnostic( + diag::err_odr_different_num_template_parameters)) << Params1->size() << Params2->size(); Context.Diag1(Params1->getTemplateLoc(), diag::note_odr_template_parameter_list); @@ -1265,7 +1412,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { if (Context.Complain) { Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); + Context.getApplicableDiagnostic( + diag::err_odr_different_template_parameter_kind)); Context.Diag1(Params1->getParam(I)->getLocation(), diag::note_odr_template_parameter_here); } @@ -1285,7 +1433,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTypeParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1301,7 +1451,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NonTypeTemplateParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1313,7 +1465,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) + Context.getApplicableDiagnostic( + diag::err_odr_non_type_parameter_type_inconsistent)) << D2->getType() << D1->getType(); Context.Diag1(D1->getLocation(), diag::note_odr_value_here) << D1->getType(); @@ -1329,7 +1482,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTemplateParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { if (Context.Complain) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + Context.Diag2(D2->getLocation(), + Context.getApplicableDiagnostic( + diag::err_odr_parameter_pack_non_pack)) << D2->isParameterPack(); Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) << D1->isParameterPack(); @@ -1378,6 +1533,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ConceptDecl *D1, + ConceptDecl *D2) { + // Check template parameters. + if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2)) + return false; + + // Check the constraint expression. + return IsStructurallyEquivalent(Context, D1->getConstraintExpr(), + D2->getConstraintExpr()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FriendDecl *D1, FriendDecl *D2) { if ((D1->getFriendType() && D2->getFriendDecl()) || (D1->getFriendDecl() && D2->getFriendType())) { @@ -1485,6 +1652,52 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { return Index; } +unsigned StructuralEquivalenceContext::getApplicableDiagnostic( + unsigned ErrorDiagnostic) { + if (ErrorOnTagTypeMismatch) + return ErrorDiagnostic; + + switch (ErrorDiagnostic) { + case diag::err_odr_variable_type_inconsistent: + return diag::warn_odr_variable_type_inconsistent; + case diag::err_odr_variable_multiple_def: + return diag::warn_odr_variable_multiple_def; + case diag::err_odr_function_type_inconsistent: + return diag::warn_odr_function_type_inconsistent; + case diag::err_odr_tag_type_inconsistent: + return diag::warn_odr_tag_type_inconsistent; + case diag::err_odr_field_type_inconsistent: + return diag::warn_odr_field_type_inconsistent; + case diag::err_odr_ivar_type_inconsistent: + return diag::warn_odr_ivar_type_inconsistent; + case diag::err_odr_objc_superclass_inconsistent: + return diag::warn_odr_objc_superclass_inconsistent; + case diag::err_odr_objc_method_result_type_inconsistent: + return diag::warn_odr_objc_method_result_type_inconsistent; + case diag::err_odr_objc_method_num_params_inconsistent: + return diag::warn_odr_objc_method_num_params_inconsistent; + case diag::err_odr_objc_method_param_type_inconsistent: + return diag::warn_odr_objc_method_param_type_inconsistent; + case diag::err_odr_objc_method_variadic_inconsistent: + return diag::warn_odr_objc_method_variadic_inconsistent; + case diag::err_odr_objc_property_type_inconsistent: + return diag::warn_odr_objc_property_type_inconsistent; + case diag::err_odr_objc_property_impl_kind_inconsistent: + return diag::warn_odr_objc_property_impl_kind_inconsistent; + case diag::err_odr_objc_synthesize_ivar_inconsistent: + return diag::warn_odr_objc_synthesize_ivar_inconsistent; + case diag::err_odr_different_num_template_parameters: + return diag::warn_odr_different_num_template_parameters; + case diag::err_odr_different_template_parameter_kind: + return diag::warn_odr_different_template_parameter_kind; + case diag::err_odr_parameter_pack_non_pack: + return diag::warn_odr_parameter_pack_non_pack; + case diag::err_odr_non_type_parameter_type_inconsistent: + return diag::warn_odr_non_type_parameter_type_inconsistent; + } + llvm_unreachable("Diagnostic kind not handled in preceding switch"); +} + bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) { // Ensure that the implementation functions (all static functions in this TU) @@ -1590,6 +1803,14 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence( // Class template/non-class-template mismatch. return false; } + } else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) { + if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2)) + return false; + } else { + // Concept/non-concept mismatch. + return false; + } } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) @@ -1624,6 +1845,12 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence( } } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { + if (FD1->isOverloadedOperator()) { + if (!FD2->isOverloadedOperator()) + return false; + if (FD1->getOverloadedOperator() != FD2->getOverloadedOperator()) + return false; + } if (!::IsStructurallyEquivalent(FD1->getIdentifier(), FD2->getIdentifier())) return false; diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp index 461084ce707ce..ba1581bd3f6b6 100644 --- a/lib/AST/ASTTypeTraits.cpp +++ b/lib/AST/ASTTypeTraits.cpp @@ -1,9 +1,8 @@ //===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -38,6 +37,9 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { { NKI_None, "Type" }, #define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" }, #include "clang/AST/TypeNodes.def" + { NKI_None, "OMPClause" }, +#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class}, +#include "clang/Basic/OpenMPKinds.def" }; bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const { @@ -104,6 +106,19 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) { #include "clang/AST/TypeNodes.def" } llvm_unreachable("invalid type kind"); + } + +ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { + switch (C.getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: return ASTNodeKind(NKI_##Class); +#include "clang/Basic/OpenMPKinds.def" + case OMPC_threadprivate: + case OMPC_uniform: + case OMPC_unknown: + llvm_unreachable("unexpected OpenMP clause kind"); + } + llvm_unreachable("invalid stmt kind"); } void DynTypedNode::print(llvm::raw_ostream &OS, @@ -152,6 +167,8 @@ SourceRange DynTypedNode::getSourceRange() const { return D->getSourceRange(); if (const Stmt *S = get<Stmt>()) return S->getSourceRange(); + if (const auto *C = get<OMPClause>()) + return SourceRange(C->getBeginLoc(), C->getEndLoc()); return SourceRange(); } diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index b06b50c9b4b88..0ef925ec1c901 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -1,9 +1,8 @@ //===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 06295b58178bf..31cb369187266 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -1,9 +1,8 @@ //===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index ddb350e72bbd0..ecf451b175afb 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -1,9 +1,8 @@ //===- CXXInheritance.cpp - C++ Inheritance -------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -487,6 +486,21 @@ bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier, return false; } +bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) { + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); + + for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper)) + return true; + } + + return false; +} + bool CXXRecordDecl:: FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, @@ -540,8 +554,7 @@ void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides = Overrides[OverriddenSubobject]; - if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), - Overriding) == SubobjectOverrides.end()) + if (llvm::find(SubobjectOverrides, Overriding) == SubobjectOverrides.end()) SubobjectOverrides.push_back(Overriding); } diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 0d759e226c427..25339c7901e30 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -1,9 +1,8 @@ //===--- Comment.cpp - Comment AST node implementation --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index 5ec7586a475d2..2b648cbb1d4b4 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -1,9 +1,8 @@ //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index 7378a7c3ac060..b306fcbb154f3 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -1,9 +1,8 @@ //===--- CommentCommandTraits.cpp - Comment command properties --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index c43275318dd76..19485f6018c02 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -1,9 +1,8 @@ //===--- CommentLexer.cpp -------------------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 7f70b95e98121..c7f8aa7e16a0a 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -1,9 +1,8 @@ //===--- CommentParser.cpp - Doxygen comment parser -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index 88588a7a89e60..067b3ae4222e3 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -1,9 +1,8 @@ //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/ComparisonCategories.cpp b/lib/AST/ComparisonCategories.cpp index 87f51facc59b9..ee4c1b0443a32 100644 --- a/lib/AST/ComparisonCategories.cpp +++ b/lib/AST/ComparisonCategories.cpp @@ -1,9 +1,8 @@ //===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DataCollection.cpp b/lib/AST/DataCollection.cpp index c2ecabe8e6f8a..8e67c101dee1f 100644 --- a/lib/AST/DataCollection.cpp +++ b/lib/AST/DataCollection.cpp @@ -1,9 +1,8 @@ //===-- DataCollection.cpp --------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5536358b1ecf1..21cf9da18a8b2 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1,9 +1,8 @@ //===- Decl.cpp - Declaration AST Node Implementation ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -568,7 +567,14 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { return false; } -static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { +/// Determine whether D is declared in the purview of a named module. +static bool isInModulePurview(const NamedDecl *D) { + if (auto *M = D->getOwningModule()) + return M->isModulePurview(); + return false; +} + +static bool isExportedFromModuleInterfaceUnit(const NamedDecl *D) { // FIXME: Handle isModulePrivate. switch (D->getModuleOwnershipKind()) { case Decl::ModuleOwnershipKind::Unowned: @@ -576,8 +582,7 @@ static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { return false; case Decl::ModuleOwnershipKind::Visible: case Decl::ModuleOwnershipKind::VisibleWhenImported: - if (auto *M = D->getOwningModule()) - return M->Kind == Module::ModuleInterfaceUnit; + return isInModulePurview(D); } llvm_unreachable("unexpected module ownership kind"); } @@ -587,9 +592,8 @@ static LinkageInfo getInternalLinkageFor(const NamedDecl *D) { // as "module-internal linkage", which means that they have internal linkage // formally but can be indirectly accessed from outside the module via inline // functions and templates defined within the module. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + if (isInModulePurview(D)) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); return LinkageInfo::internal(); } @@ -599,15 +603,25 @@ static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { // - A name declared at namespace scope that does not have internal linkage // by the previous rules and that is introduced by a non-exported // declaration has module linkage. - if (auto *M = D->getOwningModule()) - if (M->Kind == Module::ModuleInterfaceUnit) - if (!isExportedFromModuleIntefaceUnit( - cast<NamedDecl>(D->getCanonicalDecl()))) - return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + if (isInModulePurview(D) && !isExportedFromModuleInterfaceUnit( + cast<NamedDecl>(D->getCanonicalDecl()))) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); return LinkageInfo::external(); } +static StorageClass getStorageClass(const Decl *D) { + if (auto *TD = dyn_cast<TemplateDecl>(D)) + D = TD->getTemplatedDecl(); + if (D) { + if (auto *VD = dyn_cast<VarDecl>(D)) + return VD->getStorageClass(); + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getStorageClass(); + } + return SC_None; +} + LinkageInfo LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation, @@ -619,24 +633,28 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // C++ [basic.link]p3: // A name having namespace scope (3.3.6) has internal linkage if it // is the name of - // - an object, reference, function or function template that is - // explicitly declared static; or, - // (This bullet corresponds to C99 6.2.2p3.) + + if (getStorageClass(D->getCanonicalDecl()) == SC_Static) { + // - a variable, variable template, function, or function template + // that is explicitly declared static; or + // (This bullet corresponds to C99 6.2.2p3.) + return getInternalLinkageFor(D); + } + if (const auto *Var = dyn_cast<VarDecl>(D)) { - // Explicitly declared static. - if (Var->getStorageClass() == SC_Static) - return getInternalLinkageFor(Var); - - // - a non-inline, non-volatile object or reference that is explicitly - // declared const or constexpr and neither explicitly declared extern - // nor previously declared to have external linkage; or (there is no - // equivalent in C99) - // The C++ modules TS adds "non-exported" to this list. + // - a non-template variable of non-volatile const-qualified type, unless + // - it is explicitly declared extern, or + // - it is inline or exported, or + // - it was previously declared and the prior declaration did not have + // internal linkage + // (There is no equivalent in C99.) if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && !Var->isInline() && - !isExportedFromModuleIntefaceUnit(Var)) { + !isExportedFromModuleInterfaceUnit(Var) && + !isa<VarTemplateSpecializationDecl>(Var) && + !Var->getDescribedVarTemplate()) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); @@ -656,14 +674,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, if (PrevVar->getStorageClass() == SC_Static) return getInternalLinkageFor(Var); } - } else if (const FunctionDecl *Function = D->getAsFunction()) { - // C++ [temp]p4: - // A non-member function template can have internal linkage; any - // other template name shall have external linkage. - - // Explicitly declared static. - if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return getInternalLinkageFor(Function); } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); @@ -672,6 +682,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, } assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); + // FIXME: This gives internal linkage to names that should have no linkage + // (those not covered by [basic.link]p6). if (D->isInAnonymousNamespace()) { const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); @@ -731,10 +743,20 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // C++ [basic.link]p4: - // A name having namespace scope has external linkage if it is the - // name of + // A name having namespace scope that has not been given internal linkage + // above and that is the name of + // [...bullets...] + // has its linkage determined as follows: + // - if the enclosing namespace has internal linkage, the name has + // internal linkage; [handled above] + // - otherwise, if the declaration of the name is attached to a named + // module and is not exported, the name has module linkage; + // - otherwise, the name has external linkage. + // LV is currently set up to handle the last two bullets. // - // - an object or reference, unless it has internal linkage; or + // The bullets are: + + // - a variable; or if (const auto *Var = dyn_cast<VarDecl>(D)) { // GCC applies the following optimization to variables and static // data members, but not to functions: @@ -780,7 +802,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // - a function, unless it has internal linkage; or + // - a function; or } else if (const auto *Function = dyn_cast<FunctionDecl>(D)) { // In theory, we can modify the function's LV by the LV of its // type unless it has C linkage (see comment above about variables @@ -834,7 +856,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, mergeTemplateLV(LV, spec, computation); } - // - an enumerator belonging to an enumeration with external linkage; + // FIXME: This is not part of the C++ standard any more. + // - an enumerator belonging to an enumeration with external linkage; or } else if (isa<EnumConstantDecl>(D)) { LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), computation); @@ -842,16 +865,16 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, return LinkageInfo::none(); LV.merge(EnumLV); - // - a template, unless it is a function template that has - // internal linkage (Clause 14); + // - a template } else if (const auto *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); LinkageInfo tempLV = getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); - // - a namespace (7.3), unless it is declared within an unnamed - // namespace. + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. All other namespaces + // have external linkage. // // We handled names in anonymous namespaces above. } else if (isa<NamespaceDecl>(D)) { @@ -1508,6 +1531,11 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { } return InternalLinkage ? M->Parent : nullptr; } + + case Module::PrivateModuleFragment: + // The private module fragment is part of its containing module for linkage + // purposes. + return M->Parent; } llvm_unreachable("unknown module kind"); @@ -1532,10 +1560,16 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, const PrintingPolicy &P) const { const DeclContext *Ctx = getDeclContext(); - // For ObjC methods, look through categories and use the interface as context. + // For ObjC methods and properties, look through categories and use the + // interface as context. if (auto *MD = dyn_cast<ObjCMethodDecl>(this)) if (auto *ID = MD->getClassInterface()) Ctx = ID; + if (auto *PD = dyn_cast<ObjCPropertyDecl>(this)) { + if (auto *MD = PD->getGetterMethodDecl()) + if (auto *ID = MD->getClassInterface()) + Ctx = ID; + } if (Ctx->isFunctionOrMethod()) { printName(OS); @@ -2211,12 +2245,16 @@ void VarDecl::setInit(Expr *I) { Init = I; } -bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { +bool VarDecl::mightBeUsableInConstantExpressions(ASTContext &C) const { const LangOptions &Lang = C.getLangOpts(); if (!Lang.CPlusPlus) return false; + // Function parameters are never usable in constant expressions. + if (isa<ParmVarDecl>(this)) + return false; + // In C++11, any variable of reference type can be used in a constant // expression if it is initialized by a constant expression. if (Lang.CPlusPlus11 && getType()->isReferenceType()) @@ -2238,6 +2276,22 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const { return Lang.CPlusPlus11 && isConstexpr(); } +bool VarDecl::isUsableInConstantExpressions(ASTContext &Context) const { + // C++2a [expr.const]p3: + // A variable is usable in constant expressions after its initializing + // declaration is encountered... + const VarDecl *DefVD = nullptr; + const Expr *Init = getAnyInitializer(DefVD); + if (!Init || Init->isValueDependent() || getType()->isDependentType()) + return false; + // ... if it is a constexpr variable, or it is of reference type or of + // const-qualified integral or enumeration type, ... + if (!DefVD->mightBeUsableInConstantExpressions(Context)) + return false; + // ... and its initializer is a constant initializer. + return DefVD->checkInitIsICE(); +} + /// Convert the initializer for this declaration to the elaborated EvaluatedStmt /// form, which contains extra information on the evaluated value of the /// initializer. @@ -2268,7 +2322,7 @@ APValue *VarDecl::evaluateValue( // first time it is evaluated. FIXME: The notes won't always be emitted the // first time we try evaluation, so might not be produced at all. if (Eval->WasEvaluated) - return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated; + return Eval->Evaluated.isAbsent() ? nullptr : &Eval->Evaluated; const auto *Init = cast<Expr>(Eval->Value); assert(!Init->isValueDependent()); @@ -2363,6 +2417,10 @@ bool VarDecl::checkInitIsICE() const { return Eval->IsICE; } +bool VarDecl::isParameterPack() const { + return isa<PackExpansionType>(getType()); +} + template<typename DeclT> static DeclT *getDefinitionOrSelf(DeclT *D) { assert(D); @@ -2380,48 +2438,61 @@ bool VarDecl::isNonEscapingByref() const { } VarDecl *VarDecl::getTemplateInstantiationPattern() const { - // If it's a variable template specialization, find the template or partial - // specialization from which it was instantiated. - if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(this)) { - auto From = VDTemplSpec->getInstantiatedFrom(); - if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) { - while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) { - if (NewVTD->isMemberSpecialization()) - break; - VTD = NewVTD; - } - return getDefinitionOrSelf(VTD->getTemplatedDecl()); - } - if (auto *VTPSD = - From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) { - if (NewVTPSD->isMemberSpecialization()) - break; - VTPSD = NewVTPSD; - } - return getDefinitionOrSelf<VarDecl>(VTPSD); - } - } + const VarDecl *VD = this; - if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + // If this is an instantiated member, walk back to the template from which + // it was instantiated. + if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) { if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { - VarDecl *VD = getInstantiatedFromStaticDataMember(); + VD = VD->getInstantiatedFromStaticDataMember(); while (auto *NewVD = VD->getInstantiatedFromStaticDataMember()) VD = NewVD; - return getDefinitionOrSelf(VD); } } - if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) { - while (VarTemplate->getInstantiatedFromMemberTemplate()) { - if (VarTemplate->isMemberSpecialization()) + // If it's an instantiated variable template specialization, find the + // template or partial specialization from which it was instantiated. + if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(VD)) { + if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { + auto From = VDTemplSpec->getInstantiatedFrom(); + if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) { + while (!VTD->isMemberSpecialization()) { + auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); + if (!NewVTD) + break; + VTD = NewVTD; + } + return getDefinitionOrSelf(VTD->getTemplatedDecl()); + } + if (auto *VTPSD = + From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + while (!VTPSD->isMemberSpecialization()) { + auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); + if (!NewVTPSD) + break; + VTPSD = NewVTPSD; + } + return getDefinitionOrSelf<VarDecl>(VTPSD); + } + } + } + + // If this is the pattern of a variable template, find where it was + // instantiated from. FIXME: Is this necessary? + if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) { + while (!VarTemplate->isMemberSpecialization()) { + auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); + if (!NewVT) break; - VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate(); + VarTemplate = NewVT; } return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); } - return nullptr; + + if (VD == this) + return nullptr; + return getDefinitionOrSelf(const_cast<VarDecl*>(VD)); } VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { @@ -2441,6 +2512,17 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { return TSK_Undeclared; } +TemplateSpecializationKind +VarDecl::getTemplateSpecializationKindForInstantiation() const { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getTemplateSpecializationKind(); + + if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + + return TSK_Undeclared; +} + SourceLocation VarDecl::getPointOfInstantiation() const { if (const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) return Spec->getPointOfInstantiation(); @@ -2501,15 +2583,14 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, if (VarTemplateSpecializationDecl *Spec = dyn_cast<VarTemplateSpecializationDecl>(this)) { Spec->setSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && Spec->getPointOfInstantiation().isInvalid()) { Spec->setPointOfInstantiation(PointOfInstantiation); if (ASTMutationListener *L = getASTContext().getASTMutationListener()) L->InstantiationRequested(this); } - } - - if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + } else if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { MSI->setTemplateSpecializationKind(TSK); if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && MSI->getPointOfInstantiation().isInvalid()) { @@ -2626,10 +2707,6 @@ bool ParmVarDecl::hasDefaultArg() const { !Init.isNull(); } -bool ParmVarDecl::isParameterPack() const { - return isa<PackExpansionType>(getType()); -} - void ParmVarDecl::setParameterIndexLarge(unsigned parameterIndex) { getASTContext().setParameterIndex(this, parameterIndex); ParmVarDeclBits.ParameterIndex = ParameterIndexSentinel; @@ -2647,7 +2724,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, - bool isInlineSpecified, bool isConstexprSpecified) + bool isInlineSpecified, + ConstexprSpecKind ConstexprKind) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), redeclarable_base(C), ODRHash(0), @@ -2656,7 +2734,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.SClass = S; FunctionDeclBits.IsInline = isInlineSpecified; FunctionDeclBits.IsInlineSpecified = isInlineSpecified; - FunctionDeclBits.IsExplicitSpecified = false; FunctionDeclBits.IsVirtualAsWritten = false; FunctionDeclBits.IsPure = false; FunctionDeclBits.HasInheritedPrototype = false; @@ -2668,7 +2745,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsExplicitlyDefaulted = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; - FunctionDeclBits.IsConstexpr = isConstexprSpecified; + FunctionDeclBits.ConstexprKind = ConstexprKind; FunctionDeclBits.InstantiationIsPending = false; FunctionDeclBits.UsesSEHTry = false; FunctionDeclBits.HasSkippedBody = false; @@ -2904,6 +2981,8 @@ bool FunctionDecl::isExternC() const { } bool FunctionDecl::isInExternCContext() const { + if (hasAttr<OpenCLKernelAttr>()) + return true; return getLexicalDeclContext()->isExternCContext(); } @@ -2982,16 +3061,20 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } -/// Returns a value indicating whether this function -/// corresponds to a builtin function. +/// Returns a value indicating whether this function corresponds to a builtin +/// function. /// -/// The function corresponds to a built-in function if it is -/// declared at translation scope or within an extern "C" block and -/// its name matches with the name of a builtin. The returned value -/// will be 0 for functions that do not correspond to a builtin, a -/// value of type \c Builtin::ID if in the target-independent range -/// \c [1,Builtin::First), or a target-specific builtin value. -unsigned FunctionDecl::getBuiltinID() const { +/// The function corresponds to a built-in function if it is declared at +/// translation scope or within an extern "C" block and its name matches with +/// the name of a builtin. The returned value will be 0 for functions that do +/// not correspond to a builtin, a value of type \c Builtin::ID if in the +/// target-independent range \c [1,Builtin::First), or a target-specific builtin +/// value. +/// +/// \param ConsiderWrapperFunctions If true, we should consider wrapper +/// functions as their wrapped builtins. This shouldn't be done in general, but +/// it's useful in Sema to diagnose calls to wrappers based on their semantics. +unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { if (!getIdentifier()) return 0; @@ -3019,7 +3102,7 @@ unsigned FunctionDecl::getBuiltinID() const { // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (hasAttr<OverloadableAttr>()) + if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) @@ -3030,7 +3113,7 @@ unsigned FunctionDecl::getBuiltinID() const { // function or whether it just has the same name. // If this is a static function, it's not a builtin. - if (getStorageClass() == SC_Static) + if (!ConsiderWrapperFunctions && getStorageClass() == SC_Static) return 0; // OpenCL v1.2 s6.9.f - The library functions defined in @@ -3337,7 +3420,13 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { } MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { - return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>(); + if (auto *MSI = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSI; + if (auto *FTSI = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + return FTSI->getMemberSpecializationInfo(); + return nullptr; } void @@ -3356,6 +3445,8 @@ FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const { } void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); TemplateOrSpecialization = Template; } @@ -3364,19 +3455,15 @@ bool FunctionDecl::isImplicitlyInstantiable() const { if (isInvalidDecl()) return false; - switch (getTemplateSpecializationKind()) { + switch (getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: return false; case TSK_ImplicitInstantiation: return true; - // It is possible to instantiate TSK_ExplicitSpecialization kind - // if the FunctionDecl has a class scope specialization pattern. - case TSK_ExplicitSpecialization: - return getClassScopeSpecializationPattern() != nullptr; - case TSK_ExplicitInstantiationDeclaration: // Handled below. break; @@ -3399,26 +3486,12 @@ bool FunctionDecl::isImplicitlyInstantiable() const { } bool FunctionDecl::isTemplateInstantiation() const { - switch (getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return false; - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - return true; - } - llvm_unreachable("All TSK values handled."); + // FIXME: Remove this, it's not clear what it means. (Which template + // specialization kind?) + return clang::isTemplateInstantiation(getTemplateSpecializationKind()); } FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { - // Handle class scope explicit specialization special case. - if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { - if (auto *Spec = getClassScopeSpecializationPattern()) - return getDefinitionOrSelf(Spec); - return nullptr; - } - // If this is a generic lambda call operator specialization, its // instantiation pattern is always its primary template's pattern // even if its primary template was instantiated from another @@ -3434,21 +3507,28 @@ FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl()); } + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) { + if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind())) + return nullptr; + return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom())); + } + + if (!clang::isTemplateInstantiation(getTemplateSpecializationKind())) + return nullptr; + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { - while (Primary->getInstantiatedFromMemberTemplate()) { - // If we have hit a point where the user provided a specialization of - // this template, we're done looking. - if (Primary->isMemberSpecialization()) + // If we hit a point where the user provided a specialization of this + // template, we're done looking. + while (!Primary->isMemberSpecialization()) { + auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); + if (!NewPrimary) break; - Primary = Primary->getInstantiatedFromMemberTemplate(); + Primary = NewPrimary; } return getDefinitionOrSelf(Primary->getTemplatedDecl()); } - if (auto *MFD = getInstantiatedFromMemberFunction()) - return getDefinitionOrSelf(MFD); - return nullptr; } @@ -3456,15 +3536,11 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast<FunctionTemplateSpecializationInfo*>()) { - return Info->Template.getPointer(); + return Info->getTemplate(); } return nullptr; } -FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const { - return getASTContext().getClassScopeSpecializationPattern(this); -} - FunctionTemplateSpecializationInfo * FunctionDecl::getTemplateSpecializationInfo() const { return TemplateOrSpecialization @@ -3499,15 +3575,19 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, TemplateSpecializationKind TSK, const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation PointOfInstantiation) { + assert((TemplateOrSpecialization.isNull() || + TemplateOrSpecialization.is<MemberSpecializationInfo *>()) && + "Member function is already a specialization"); assert(TSK != TSK_Undeclared && "Must specify the type of function template specialization"); - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (!Info) - Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, - TemplateArgs, - TemplateArgsAsWritten, - PointOfInstantiation); + assert((TemplateOrSpecialization.isNull() || + TSK == TSK_ExplicitSpecialization) && + "Member specialization must be an explicit specialization"); + FunctionTemplateSpecializationInfo *Info = + FunctionTemplateSpecializationInfo::Create( + C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten, + PointOfInstantiation, + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()); TemplateOrSpecialization = Info; Template->addSpecialization(Info, InsertPos); } @@ -3558,14 +3638,47 @@ DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. - FunctionTemplateSpecializationInfo *FTSInfo - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (FTSInfo) + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + return FTSInfo->getTemplateSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +TemplateSpecializationKind +FunctionDecl::getTemplateSpecializationKindForInstantiation() const { + // This is the same as getTemplateSpecializationKind(), except that for a + // function that is both a function template specialization and a member + // specialization, we prefer the member specialization information. Eg: + // + // template<typename T> struct A { + // template<typename U> void f() {} + // template<> void f<int>() {} + // }; + // + // For A<int>::f<int>(): + // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization + // * getTemplateSpecializationKindForInstantiation() will return + // TSK_ImplicitInstantiation + // + // This reflects the facts that A<int>::f<int> is an explicit specialization + // of A<int>::f, and that A<int>::f<int> should be implicitly instantiated + // from A::f<int> if a definition is needed. + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) { + if (auto *MSInfo = FTSInfo->getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); return FTSInfo->getTemplateSpecializationKind(); + } - MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); - if (MSInfo) + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; @@ -3673,6 +3786,10 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { case Builtin::BImemcmp: return Builtin::BImemcmp; + case Builtin::BI__builtin_bcmp: + case Builtin::BIbcmp: + return Builtin::BIbcmp; + case Builtin::BI__builtin_strncpy: case Builtin::BI__builtin___strncpy_chk: case Builtin::BIstrncpy: @@ -3713,6 +3830,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { return Builtin::BImemmove; else if (FnInfo->isStr("memcmp")) return Builtin::BImemcmp; + else if (FnInfo->isStr("bcmp")) + return Builtin::BIbcmp; else if (FnInfo->isStr("strncpy")) return Builtin::BIstrncpy; else if (FnInfo->isStr("strncmp")) @@ -3794,6 +3913,39 @@ bool FieldDecl::isZeroLengthBitField(const ASTContext &Ctx) const { getBitWidthValue(Ctx) == 0; } +bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { + if (isZeroLengthBitField(Ctx)) + return true; + + // C++2a [intro.object]p7: + // An object has nonzero size if it + // -- is not a potentially-overlapping subobject, or + if (!hasAttr<NoUniqueAddressAttr>()) + return false; + + // -- is not of class type, or + const auto *RT = getType()->getAs<RecordType>(); + if (!RT) + return false; + const RecordDecl *RD = RT->getDecl()->getDefinition(); + if (!RD) { + assert(isInvalidDecl() && "valid field has incomplete type"); + return false; + } + + // -- [has] virtual member functions or virtual base classes, or + // -- has subobjects of nonzero size or bit-fields of nonzero length + const auto *CXXRD = cast<CXXRecordDecl>(RD); + if (!CXXRD->isEmpty()) + return false; + + // Otherwise, [...] the circumstances under which the object has zero size + // are implementation-defined. + // FIXME: This might be Itanium ABI specific; we don't yet know what the MS + // ABI will do. + return true; +} + unsigned FieldDecl::getFieldIndex() const { const FieldDecl *Canonical = getCanonicalDecl(); if (Canonical != this) @@ -4100,6 +4252,9 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, setNonTrivialToPrimitiveDefaultInitialize(false); setNonTrivialToPrimitiveCopy(false); setNonTrivialToPrimitiveDestroy(false); + setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false); + setHasNonTrivialToPrimitiveDestructCUnion(false); + setHasNonTrivialToPrimitiveCopyCUnion(false); setParamDestroyedInCallee(false); setArgPassingRestrictions(APK_CanPassInRegs); } @@ -4260,6 +4415,7 @@ BlockDecl::BlockDecl(DeclContext *DC, SourceLocation CaretLoc) setBlockMissingReturnType(true); setIsConversionFromLambda(false); setDoesNotEscape(false); + setCanAvoidCopyToHeap(false); } void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { @@ -4422,13 +4578,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, - bool isInlineSpecified, + StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, - bool isConstexprSpecified) { + ConstexprSpecKind ConstexprKind) { FunctionDecl *New = new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, - SC, isInlineSpecified, isConstexprSpecified); + SC, isInlineSpecified, ConstexprKind); New->setHasWrittenPrototype(hasWrittenPrototype); return New; } @@ -4436,7 +4591,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - SC_None, false, false); + SC_None, false, CSK_unspecified); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index b83082e9eb08c..fd80e1532eb5d 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -1,9 +1,8 @@ //===- DeclBase.cpp - Declaration AST Node Implementation -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -209,8 +208,8 @@ bool Decl::isTemplateParameterPack() const { } bool Decl::isParameterPack() const { - if (const auto *Parm = dyn_cast<ParmVarDecl>(this)) - return Parm->isParameterPack(); + if (const auto *Var = dyn_cast<VarDecl>(this)) + return Var->isParameterPack(); return isTemplateParameterPack(); } @@ -355,7 +354,8 @@ bool Decl::isInAnonymousNamespace() const { } bool Decl::isInStdNamespace() const { - return getDeclContext()->isStdNamespace(); + const DeclContext *DC = getDeclContext(); + return DC && DC->isStdNamespace(); } TranslationUnitDecl *Decl::getTranslationUnitDecl() { @@ -431,22 +431,6 @@ bool Decl::isReferenced() const { return false; } -bool Decl::isExported() const { - if (isModulePrivate()) - return false; - // Namespaces are always exported. - if (isa<TranslationUnitDecl>(this) || isa<NamespaceDecl>(this)) - return true; - // Otherwise, this is a strictly lexical check. - for (auto *DC = getLexicalDeclContext(); DC; DC = DC->getLexicalParent()) { - if (cast<Decl>(DC)->isModulePrivate()) - return false; - if (isa<ExportDecl>(DC)) - return true; - } - return false; -} - ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const { const Decl *Definition = nullptr; if (auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) { @@ -726,6 +710,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Binding: case NonTypeTemplateParm: case VarTemplate: + case Concept: // These (C++-only) declarations are found by redeclaration lookup for // tag types, so we include them in the tag namespace. return IDNS_Ordinary | IDNS_Tag; @@ -781,6 +766,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OMPDeclareReduction: return IDNS_OMPReduction; + case OMPDeclareMapper: + return IDNS_OMPMapper; + // Never have names. case Friend: case FriendTemplate: @@ -810,6 +798,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCategoryImpl: case Import: case OMPThreadPrivate: + case OMPAllocate: case OMPRequires: case OMPCapturedExpr: case Empty: @@ -932,6 +921,7 @@ bool Decl::AccessDeclContextSanity() const { if (isa<TranslationUnitDecl>(this) || isa<TemplateTypeParmDecl>(this) || isa<NonTypeTemplateParmDecl>(this) || + !getDeclContext() || !isa<CXXRecordDecl>(getDeclContext()) || isInvalidDecl() || isa<StaticAssertDecl>(this) || @@ -969,6 +959,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { if (Ty->isFunctionPointerType()) Ty = Ty->getAs<PointerType>()->getPointeeType(); + else if (Ty->isFunctionReferenceType()) + Ty = Ty->getAs<ReferenceType>()->getPointeeType(); else if (BlocksToo && Ty->isBlockPointerType()) Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); @@ -1054,6 +1046,18 @@ DeclContext *DeclContext::getLookupParent() { return getParent(); } +const BlockDecl *DeclContext::getInnermostBlockDecl() const { + const DeclContext *Ctx = this; + + do { + if (Ctx->isClosure()) + return cast<BlockDecl>(Ctx); + Ctx = Ctx->getParent(); + } while (Ctx); + + return nullptr; +} + bool DeclContext::isInlineNamespace() const { return isNamespace() && cast<NamespaceDecl>(this)->isInline(); @@ -1164,6 +1168,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::Block: case Decl::Captured: case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: // There is only one DeclContext for these entities. return this; @@ -1175,13 +1180,15 @@ DeclContext *DeclContext::getPrimaryContext() { return this; case Decl::ObjCInterface: - if (auto *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) - return Def; + if (auto *OID = dyn_cast<ObjCInterfaceDecl>(this)) + if (auto *Def = OID->getDefinition()) + return Def; return this; case Decl::ObjCProtocol: - if (auto *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) - return Def; + if (auto *OPD = dyn_cast<ObjCProtocolDecl>(this)) + if (auto *Def = OPD->getDefinition()) + return Def; return this; case Decl::ObjCCategory: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 31ffeb0dcd1e2..59710a55498f2 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1,9 +1,8 @@ //===- DeclCXX.cpp - C++ Declaration AST Node Implementation --------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -606,14 +605,19 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( // that sure looks like a wording bug. // -- If X is a non-union class type with a non-static data member - // [recurse to] the first non-static data member of X + // [recurse to each field] that is either of zero size or is the + // first non-static data member of X // -- If X is a union type, [recurse to union members] + bool IsFirstField = true; for (auto *FD : X->fields()) { // FIXME: Should we really care about the type of the first non-static // data member of a non-union if there are preceding unnamed bit-fields? if (FD->isUnnamedBitfield()) continue; + if (!IsFirstField && !FD->isZeroSize(Ctx)) + continue; + // -- If X is n array type, [visit the element type] QualType T = Ctx.getBaseElementType(FD->getType()); if (auto *RD = T->getAsCXXRecordDecl()) @@ -621,7 +625,7 @@ bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( return true; if (!X->isUnion()) - break; + IsFirstField = false; } } @@ -641,7 +645,8 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const { // C++17 [expr.prim.lambda]p21: // The closure type associated with a lambda-expression has no default // constructor and a deleted copy assignment operator. - if (getLambdaCaptureDefault() != LCD_None) + if (getLambdaCaptureDefault() != LCD_None || + getLambdaData().NumCaptures != 0) return false; return getASTContext().getLangOpts().CPlusPlus2a; } @@ -992,6 +997,17 @@ void CXXRecordDecl::addedMember(Decl *D) { setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); Data.HasIrrelevantDestructor = false; + + if (isUnion()) { + data().DefaultedCopyConstructorIsDeleted = true; + data().DefaultedMoveConstructorIsDeleted = true; + data().DefaultedMoveAssignmentIsDeleted = true; + data().DefaultedDestructorIsDeleted = true; + data().NeedOverloadResolutionForCopyConstructor = true; + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForMoveAssignment = true; + data().NeedOverloadResolutionForDestructor = true; + } } else if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); } @@ -1058,6 +1074,10 @@ void CXXRecordDecl::addedMember(Decl *D) { if (T->isReferenceType()) data().DefaultedMoveAssignmentIsDeleted = true; + // Bitfields of length 0 are also zero-sized, but we already bailed out for + // those because they are always unnamed. + bool IsZeroSize = Field->isZeroSize(Context); + if (const auto *RecordTy = T->getAs<RecordType>()) { auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { @@ -1173,7 +1193,8 @@ void CXXRecordDecl::addedMember(Decl *D) { // A standard-layout class is a class that: // [...] // -- has no element of the set M(S) of types as a base class. - if (data().IsStandardLayout && (isUnion() || IsFirstField) && + if (data().IsStandardLayout && + (isUnion() || IsFirstField || IsZeroSize) && hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec)) data().IsStandardLayout = false; @@ -1255,8 +1276,10 @@ void CXXRecordDecl::addedMember(Decl *D) { } // C++14 [meta.unary.prop]p4: - // T is a class type [...] with [...] no non-static data members - data().Empty = false; + // T is a class type [...] with [...] no non-static data members other + // than subobjects of zero size + if (data().Empty && !IsZeroSize) + data().Empty = false; } // Handle using declarations of conversion functions. @@ -1411,13 +1434,28 @@ void CXXRecordDecl::getCaptureFields( TemplateParameterList * CXXRecordDecl::getGenericLambdaTemplateParameterList() const { - if (!isLambda()) return nullptr; + if (!isGenericLambda()) return nullptr; CXXMethodDecl *CallOp = getLambdaCallOperator(); if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) return Tmpl->getTemplateParameters(); return nullptr; } +ArrayRef<NamedDecl *> +CXXRecordDecl::getLambdaExplicitTemplateParameters() const { + TemplateParameterList *List = getGenericLambdaTemplateParameterList(); + if (!List) + return {}; + + assert(std::is_partitioned(List->begin(), List->end(), + [](const NamedDecl *D) { return !D->isImplicit(); }) + && "Explicit template params should be ordered before implicit ones"); + + const auto ExplicitEnd = llvm::partition_point( + *List, [](const NamedDecl *D) { return !D->isImplicit(); }); + return llvm::makeArrayRef(List->begin(), ExplicitEnd); +} + Decl *CXXRecordDecl::getLambdaContextDecl() const { assert(isLambda() && "Not a lambda closure type!"); ExternalASTSource *Source = getParentASTContext().getExternalSource(); @@ -1586,8 +1624,8 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); - assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end() - && "conversion was found multiple times in unresolved set"); + assert(llvm::find(Convs, ConvDecl) == Convs.end() && + "conversion was found multiple times in unresolved set"); return; } } @@ -1852,19 +1890,47 @@ bool CXXRecordDecl::mayBeAbstract() const { void CXXDeductionGuideDecl::anchor() {} +bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const { + if ((getKind() != Other.getKind() || + getKind() == ExplicitSpecKind::Unresolved)) { + if (getKind() == ExplicitSpecKind::Unresolved && + Other.getKind() == ExplicitSpecKind::Unresolved) { + ODRHash SelfHash, OtherHash; + SelfHash.AddStmt(getExpr()); + OtherHash.AddStmt(Other.getExpr()); + return SelfHash.CalculateHash() == OtherHash.CalculateHash(); + } else + return false; + } + return true; +} + +ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) { + switch (Function->getDeclKind()) { + case Decl::Kind::CXXConstructor: + return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXConversion: + return cast<CXXConversionDecl>(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXDeductionGuide: + return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier(); + default: + return {}; + } +} + CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create( - ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit, - const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - SourceLocation EndLocation) { - return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit, - NameInfo, T, TInfo, EndLocation); + ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, SourceLocation EndLocation) { + return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, + TInfo, EndLocation); } CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false, - DeclarationNameInfo(), QualType(), - nullptr, SourceLocation()); + return new (C, ID) CXXDeductionGuideDecl( + C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(), + QualType(), nullptr, SourceLocation()); } void CXXMethodDecl::anchor() {} @@ -1891,8 +1957,8 @@ static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, } CXXMethodDecl * -CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, - bool MayBeBase) { +CXXMethodDecl::getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD, + bool MayBeBase) { if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl()) return this; @@ -1918,6 +1984,15 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return MD; } + return nullptr; +} + +CXXMethodDecl * +CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, + bool MayBeBase) { + if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase)) + return MD; + for (const auto &I : RD->bases()) { const RecordType *RT = I.getType()->getAs<RecordType>(); if (!RT) @@ -1931,22 +2006,22 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return nullptr; } -CXXMethodDecl * -CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool isInline, - bool isConstexpr, SourceLocation EndLocation) { - return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, - T, TInfo, SC, isInline, isConstexpr, - EndLocation); +CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool isInline, + ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation) { + return new (C, RD) + CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, + isInline, ConstexprKind, EndLocation); } CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), nullptr, - SC_None, false, false, SourceLocation()); + return new (C, ID) CXXMethodDecl( + CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), + QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation()); } CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, @@ -2081,8 +2156,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction( return false; // In C++17 onwards, all potential usual deallocation functions are actual - // usual deallocation functions. - if (Context.getLangOpts().AlignedAllocation) + // usual deallocation functions. Honor this behavior when post-C++14 + // deallocation functions are offered as extensions too. + // FIXME(EricWF): Destrying Delete should be a language option. How do we + // handle when destroying delete is used prior to C++17? + if (Context.getLangOpts().CPlusPlus17 || + Context.getLangOpts().AlignedAllocation || + isDestroyingOperatorDelete()) return true; // This function is a usual deallocation function if there are no @@ -2173,12 +2253,23 @@ CXXMethodDecl::overridden_methods() const { return getASTContext().overridden_methods(this); } +static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT, + const CXXRecordDecl *Decl) { + QualType ClassTy = C.getTypeDeclType(Decl); + return C.getQualifiedType(ClassTy, FPT->getMethodQuals()); +} + QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT, const CXXRecordDecl *Decl) { ASTContext &C = Decl->getASTContext(); - QualType ClassTy = C.getTypeDeclType(Decl); - ClassTy = C.getQualifiedType(ClassTy, FPT->getTypeQuals()); - return C.getPointerType(ClassTy); + QualType ObjectTy = ::getThisObjectType(C, FPT, Decl); + return C.getPointerType(ObjectTy); +} + +QualType CXXMethodDecl::getThisObjectType(const FunctionProtoType *FPT, + const CXXRecordDecl *Decl) { + ASTContext &C = Decl->getASTContext(); + return ::getThisObjectType(C, FPT, Decl); } QualType CXXMethodDecl::getThisType() const { @@ -2193,6 +2284,14 @@ QualType CXXMethodDecl::getThisType() const { getParent()); } +QualType CXXMethodDecl::getThisObjectType() const { + // Ditto getThisType. + assert(isInstance() && "No 'this' for static methods!"); + + return CXXMethodDecl::getThisObjectType(getType()->getAs<FunctionProtoType>(), + getParent()); +} + bool CXXMethodDecl::hasInlineBody() const { // If this function is a template instantiation, look at the template from // which it was instantiated. @@ -2297,47 +2396,55 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl::CXXConstructorDecl( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared, - bool isConstexpr, InheritedConstructor Inherited) + ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, SourceLocation()) { + SC_None, isInline, ConstexprKind, SourceLocation()) { setNumCtorInitializers(0); setInheritingConstructor(static_cast<bool>(Inherited)); setImplicit(isImplicitlyDeclared); + CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0; if (Inherited) *getTrailingObjects<InheritedConstructor>() = Inherited; - setExplicitSpecified(isExplicitSpecified); + setExplicitSpecifier(ES); } void CXXConstructorDecl::anchor() {} CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID, - bool Inherited) { - unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited); - auto *Result = new (C, ID, Extra) CXXConstructorDecl( - C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - false, false, false, false, InheritedConstructor()); - Result->setInheritingConstructor(Inherited); + uint64_t AllocKind) { + bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit); + bool isInheritingConstructor = + static_cast<bool>(AllocKind & TAKInheritsConstructor); + unsigned Extra = + additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>( + isInheritingConstructor, hasTraillingExplicit); + auto *Result = new (C, ID, Extra) + CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), + QualType(), nullptr, ExplicitSpecifier(), false, false, + CSK_unspecified, InheritedConstructor()); + Result->setInheritingConstructor(isInheritingConstructor); + Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier = + hasTraillingExplicit; + Result->setExplicitSpecifier(ExplicitSpecifier()); return Result; } -CXXConstructorDecl * -CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isExplicit, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr, - InheritedConstructor Inherited) { +CXXConstructorDecl *CXXConstructorDecl::Create( + ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); unsigned Extra = - additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0); - return new (C, RD, Extra) CXXConstructorDecl( - C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared, isConstexpr, Inherited); + additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>( + Inherited ? 1 : 0, ES.getExpr() ? 1 : 0); + return new (C, RD, Extra) + CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline, + isImplicitlyDeclared, ConstexprKind, Inherited); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -2488,25 +2595,22 @@ void CXXConversionDecl::anchor() {} CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), - nullptr, false, false, false, - SourceLocation()); + return new (C, ID) CXXConversionDecl( + C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, + false, ExplicitSpecifier(), CSK_unspecified, SourceLocation()); } -CXXConversionDecl * -CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit, - bool isConstexpr, SourceLocation EndLocation) { +CXXConversionDecl *CXXConversionDecl::Create( + ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, - isInline, isExplicit, isConstexpr, - EndLocation); + return new (C, RD) + CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES, + ConstexprKind, EndLocation); } bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { @@ -2857,6 +2961,12 @@ BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); } +ValueDecl *BindingDecl::getDecomposedDecl() const { + ExternalASTSource *Source = + Decomp.isOffset() ? getASTContext().getExternalSource() : nullptr; + return cast_or_null<ValueDecl>(Decomp.get(Source)); +} + VarDecl *BindingDecl::getHoldingVar() const { Expr *B = getBinding(); if (!B) diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 08fbed3615790..8ec1dea84df5f 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -1,9 +1,8 @@ //===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index f74ef9bbb8391..27dbdaab6f30d 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -1,9 +1,8 @@ //===- DeclGroup.cpp - Classes for representing groups of Decls -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 1ed7fc71b025a..bf748fbab8e96 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -1,9 +1,8 @@ //===- DeclObjC.cpp - ObjC Declaration AST Node Implementation ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -1642,7 +1641,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { if (!layout.empty()) { // Order synthesized ivars by their size. - std::stable_sort(layout.begin(), layout.end()); + llvm::stable_sort(layout); unsigned Ix = 0, EIx = layout.size(); if (!data().IvarList) { data().IvarList = layout[0].Ivar; Ix++; diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index b77a67cbf38da..af321280d417a 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -1,9 +1,8 @@ //===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -54,6 +53,49 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { } //===----------------------------------------------------------------------===// +// OMPAllocateDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPAllocateDecl::anchor() { } + +OMPAllocateDecl *OMPAllocateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, ArrayRef<Expr *> VL, + ArrayRef<OMPClause *> CL) { + OMPAllocateDecl *D = new ( + C, DC, additionalSizeToAlloc<Expr *, OMPClause *>(VL.size(), CL.size())) + OMPAllocateDecl(OMPAllocate, DC, L); + D->NumVars = VL.size(); + D->setVars(VL); + D->NumClauses = CL.size(); + D->setClauses(CL); + return D; +} + +OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NVars, + unsigned NClauses) { + OMPAllocateDecl *D = + new (C, ID, additionalSizeToAlloc<Expr *, OMPClause *>(NVars, NClauses)) + OMPAllocateDecl(OMPAllocate, nullptr, SourceLocation()); + D->NumVars = NVars; + D->NumClauses = NClauses; + return D; +} + +void OMPAllocateDecl::setVars(ArrayRef<Expr *> VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>()); +} + +void OMPAllocateDecl::setClauses(ArrayRef<OMPClause *> CL) { + assert(CL.size() == NumClauses && + "Number of variables is not the same as the preallocated buffer"); + std::uninitialized_copy(CL.begin(), CL.end(), + getTrailingObjects<OMPClause *>()); +} + +//===----------------------------------------------------------------------===// // OMPRequiresDecl Implementation. //===----------------------------------------------------------------------===// @@ -124,6 +166,66 @@ OMPDeclareReductionDecl::getPrevDeclInScope() const { } //===----------------------------------------------------------------------===// +// OMPDeclareMapperDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareMapperDecl::anchor() {} + +OMPDeclareMapperDecl * +OMPDeclareMapperDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, QualType T, + DeclarationName VarName, + OMPDeclareMapperDecl *PrevDeclInScope) { + return new (C, DC) OMPDeclareMapperDecl(OMPDeclareMapper, DC, L, Name, T, + VarName, PrevDeclInScope); +} + +OMPDeclareMapperDecl *OMPDeclareMapperDecl::CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned N) { + auto *D = new (C, ID) + OMPDeclareMapperDecl(OMPDeclareMapper, /*DC=*/nullptr, SourceLocation(), + DeclarationName(), QualType(), DeclarationName(), + /*PrevDeclInScope=*/nullptr); + if (N) { + auto **ClauseStorage = C.Allocate<OMPClause *>(N); + D->Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, N); + } + return D; +} + +/// Creates an array of clauses to this mapper declaration and intializes +/// them. The space used to store clause pointers is dynamically allocated, +/// because we do not know the number of clauses when creating +/// OMPDeclareMapperDecl +void OMPDeclareMapperDecl::CreateClauses(ASTContext &C, + ArrayRef<OMPClause *> CL) { + assert(Clauses.empty() && "Number of clauses should be 0 on initialization"); + size_t NumClauses = CL.size(); + if (NumClauses) { + auto **ClauseStorage = C.Allocate<OMPClause *>(NumClauses); + Clauses = llvm::makeMutableArrayRef<OMPClause *>(ClauseStorage, NumClauses); + setClauses(CL); + } +} + +void OMPDeclareMapperDecl::setClauses(ArrayRef<OMPClause *> CL) { + assert(CL.size() == Clauses.size() && + "Number of clauses is not the same as the preallocated buffer"); + std::uninitialized_copy(CL.begin(), CL.end(), Clauses.data()); +} + +OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() { + return cast_or_null<OMPDeclareMapperDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} + +const OMPDeclareMapperDecl *OMPDeclareMapperDecl::getPrevDeclInScope() const { + return cast_or_null<OMPDeclareMapperDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} + +//===----------------------------------------------------------------------===// // OMPCapturedExprDecl Implementation. //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 517851f9eeb19..f5c69944034a5 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -1,9 +1,8 @@ //===--- DeclPrinter.cpp - Printing implementation for Decl ASTs ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -16,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -100,11 +100,14 @@ namespace { void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPAllocateDecl(OMPAllocateDecl *D); void VisitOMPRequiresDecl(OMPRequiresDecl *D); void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); + void VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); - void printTemplateParameters(const TemplateParameterList *Params); + void printTemplateParameters(const TemplateParameterList *Params, + bool OmitTemplateKW = false); void printTemplateArguments(const TemplateArgumentList &Args, const TemplateParameterList *Params = nullptr); void prettyPrintAttributes(Decl *D); @@ -125,6 +128,18 @@ void Decl::print(raw_ostream &Out, const PrintingPolicy &Policy, Printer.Visit(const_cast<Decl*>(this)); } +void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, + bool OmitTemplateKW) const { + print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW); +} + +void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context, + const PrintingPolicy &Policy, + bool OmitTemplateKW) const { + DeclPrinter Printer(Out, Policy, Context); + Printer.printTemplateParameters(this, OmitTemplateKW); +} + static QualType GetBaseType(QualType T) { // FIXME: This should be on the Type class! QualType BaseType = T; @@ -424,7 +439,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = nullptr; if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D) || - isa<OMPRequiresDecl>(*D)) + isa<OMPDeclareMapperDecl>(*D) || isa<OMPRequiresDecl>(*D) || + isa<OMPAllocateDecl>(*D)) Terminator = nullptr; else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->hasBody()) Terminator = nullptr; @@ -550,6 +566,21 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { } } +static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out, + PrintingPolicy &Policy, + unsigned Indentation) { + std::string Proto = "explicit"; + llvm::raw_string_ostream EOut(Proto); + if (ES.getExpr()) { + EOut << "("; + ES.getExpr()->printPretty(EOut, nullptr, Policy, Indentation); + EOut << ")"; + } + EOut << " "; + EOut.flush(); + Out << EOut.str(); +} + void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && !D->isFunctionTemplateSpecialization()) @@ -579,11 +610,12 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->isInlineSpecified()) Out << "inline "; if (D->isVirtualAsWritten()) Out << "virtual "; if (D->isModulePrivate()) Out << "__module_private__ "; - if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr "; - if ((CDecl && CDecl->isExplicitSpecified()) || - (ConversionDecl && ConversionDecl->isExplicitSpecified()) || - (GuideDecl && GuideDecl->isExplicitSpecified())) - Out << "explicit "; + if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted()) + Out << "constexpr "; + if (D->isConsteval()) Out << "consteval "; + ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D); + if (ExplicitSpec.isSpecified()) + printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation); } PrintingPolicy SubPolicy(Policy); @@ -986,25 +1018,35 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { Visit(*D->decls_begin()); } -void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) { +void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, + bool OmitTemplateKW) { assert(Params); - Out << "template <"; + if (!OmitTemplateKW) + Out << "template "; + Out << '<'; + + bool NeedComma = false; + for (const Decl *Param : *Params) { + if (Param->isImplicit()) + continue; - for (unsigned i = 0, e = Params->size(); i != e; ++i) { - if (i != 0) + if (NeedComma) Out << ", "; + else + NeedComma = true; - const Decl *Param = Params->getParam(i); if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { if (TTP->wasDeclaredWithTypename()) - Out << "typename "; + Out << "typename"; else - Out << "class "; + Out << "class"; if (TTP->isParameterPack()) - Out << "..."; + Out << " ..."; + else if (!TTP->getName().empty()) + Out << ' '; Out << *TTP; @@ -1029,7 +1071,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) { } } - Out << "> "; + Out << '>'; + if (!OmitTemplateKW) + Out << ' '; } void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args, @@ -1079,8 +1123,13 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { if (TTP->isParameterPack()) Out << "..."; Out << D->getName(); - } else { - Visit(D->getTemplatedDecl()); + } else if (auto *TD = D->getTemplatedDecl()) + Visit(TD); + else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) { + Out << "concept " << Concept->getName() << " = " ; + Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, + Indentation); + Out << ";"; } } @@ -1389,6 +1438,13 @@ void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { /// PrintObjCPropertyDecl - print a property declaration. /// +/// Print attributes in the following order: +/// - class +/// - nonatomic | atomic +/// - assign | retain | strong | copy | weak | unsafe_unretained +/// - readwrite | readonly +/// - getter & setter +/// - nullability void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required) Out << "@required\n"; @@ -1400,58 +1456,69 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { Out << "@property"; if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { bool first = true; - Out << " ("; - if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_readonly) { - Out << (first ? ' ' : ',') << "readonly"; + Out << "("; + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_class) { + Out << (first ? "" : ", ") << "class"; first = false; } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { - Out << (first ? ' ' : ',') << "getter = "; - PDecl->getGetterName().print(Out); + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_nonatomic) { + Out << (first ? "" : ", ") << "nonatomic"; first = false; } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { - Out << (first ? ' ' : ',') << "setter = "; - PDecl->getSetterName().print(Out); + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Out << (first ? "" : ", ") << "atomic"; first = false; } if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { - Out << (first ? ' ' : ',') << "assign"; - first = false; - } - - if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_readwrite) { - Out << (first ? ' ' : ',') << "readwrite"; + Out << (first ? "" : ", ") << "assign"; first = false; } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { - Out << (first ? ' ' : ',') << "retain"; + Out << (first ? "" : ", ") << "retain"; first = false; } if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_strong) { - Out << (first ? ' ' : ',') << "strong"; + Out << (first ? "" : ", ") << "strong"; first = false; } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { - Out << (first ? ' ' : ',') << "copy"; + Out << (first ? "" : ", ") << "copy"; + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) { + Out << (first ? "" : ", ") << "weak"; + first = false; + } + if (PDecl->getPropertyAttributes() + & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) { + Out << (first ? "" : ", ") << "unsafe_unretained"; first = false; } if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_nonatomic) { - Out << (first ? ' ' : ',') << "nonatomic"; + ObjCPropertyDecl::OBJC_PR_readwrite) { + Out << (first ? "" : ", ") << "readwrite"; first = false; } if (PDecl->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_atomic) { - Out << (first ? ' ' : ',') << "atomic"; + ObjCPropertyDecl::OBJC_PR_readonly) { + Out << (first ? "" : ", ") << "readonly"; + first = false; + } + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { + Out << (first ? "" : ", ") << "getter = "; + PDecl->getGetterName().print(Out); + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { + Out << (first ? "" : ", ") << "setter = "; + PDecl->getSetterName().print(Out); first = false; } @@ -1461,25 +1528,24 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { if (*nullability == NullabilityKind::Unspecified && (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_null_resettable)) { - Out << (first ? ' ' : ',') << "null_resettable"; + Out << (first ? "" : ", ") << "null_resettable"; } else { - Out << (first ? ' ' : ',') + Out << (first ? "" : ", ") << getNullabilitySpelling(*nullability, true); } first = false; } } - if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_class) { - Out << (first ? ' ' : ',') << "class"; - first = false; - } - (void) first; // Silence dead store warning due to idiomatic code. - Out << " )"; + Out << ")"; } - Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(T). - getAsString(Policy) << ' ' << *PDecl; + std::string TypeStr = PDecl->getASTContext().getUnqualifiedObjCPointerType(T). + getAsString(Policy); + Out << ' ' << TypeStr; + if (!StringRef(TypeStr).endswith("*")) + Out << ' '; + Out << *PDecl; if (Policy.PolishForDeclaration) Out << ';'; } @@ -1546,6 +1612,26 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { } } +void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) { + Out << "#pragma omp allocate"; + if (!D->varlist_empty()) { + for (OMPAllocateDecl::varlist_iterator I = D->varlist_begin(), + E = D->varlist_end(); + I != E; ++I) { + Out << (I == D->varlist_begin() ? '(' : ','); + NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl(); + ND->printQualifiedName(Out); + } + Out << ")"; + } + if (!D->clauselist_empty()) { + Out << " "; + OMPClausePrinter Printer(Out, Policy); + for (OMPClause *C : D->clauselists()) + Printer.Visit(C); + } +} + void DeclPrinter::VisitOMPRequiresDecl(OMPRequiresDecl *D) { Out << "#pragma omp requires "; if (!D->clauselist_empty()) { @@ -1559,14 +1645,8 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { if (!D->isInvalidDecl()) { Out << "#pragma omp declare reduction ("; if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) { - static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - nullptr, -#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; const char *OpName = - OperatorNames[D->getDeclName().getCXXOverloadedOperator()]; + getOperatorSpelling(D->getDeclName().getCXXOverloadedOperator()); assert(OpName && "not an overloaded operator"); Out << OpName; } else { @@ -1598,6 +1678,25 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { } } +void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { + if (!D->isInvalidDecl()) { + Out << "#pragma omp declare mapper ("; + D->printName(Out); + Out << " : "; + D->getType().print(Out, Policy); + Out << " "; + Out << D->getVarName(); + Out << ")"; + if (!D->clauselist_empty()) { + OMPClausePrinter Printer(Out, Policy); + for (auto *C : D->clauselists()) { + Out << " "; + Printer.Visit(C); + } + } + } +} + void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { D->getInit()->printPretty(Out, nullptr, Policy, Indentation); } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 76f29dac1647d..40c39c845db63 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -1,9 +1,8 @@ //===- DeclTemplate.cpp - Template Declaration AST Node Implementation ----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -688,22 +687,20 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, return new (Mem) TemplateArgumentList(Args); } -FunctionTemplateSpecializationInfo * -FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD, - FunctionTemplateDecl *Template, - TemplateSpecializationKind TSK, - const TemplateArgumentList *TemplateArgs, - const TemplateArgumentListInfo *TemplateArgsAsWritten, - SourceLocation POI) { +FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create( + ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI, + MemberSpecializationInfo *MSInfo) { const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; if (TemplateArgsAsWritten) ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C, *TemplateArgsAsWritten); - return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK, - TemplateArgs, - ArgsAsWritten, - POI); + void *Mem = + C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0)); + return new (Mem) FunctionTemplateSpecializationInfo( + FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo); } //===----------------------------------------------------------------------===// @@ -825,6 +822,26 @@ ClassTemplateSpecializationDecl::getSourceRange() const { } //===----------------------------------------------------------------------===// +// ConceptDecl Implementation +//===----------------------------------------------------------------------===// +ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + Expr *ConstraintExpr) { + AdoptTemplateParameterList(Params, DC); + return new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr); +} + +ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(), + DeclarationName(), + nullptr, nullptr); + + return Result; +} + +//===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// void ClassTemplatePartialSpecializationDecl::anchor() {} @@ -936,7 +953,7 @@ ClassScopeFunctionSpecializationDecl * ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ClassScopeFunctionSpecializationDecl( - nullptr, SourceLocation(), nullptr, false, TemplateArgumentListInfo()); + nullptr, SourceLocation(), nullptr, nullptr); } //===----------------------------------------------------------------------===// @@ -957,6 +974,7 @@ VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, VarDecl *Decl) { + AdoptTemplateParameterList(Params, DC); return new (C, DC) VarTemplateDecl(C, DC, L, Name, Params, Decl); } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index f2c152f918ebf..fe69c71aa3ddf 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -1,9 +1,8 @@ //===- DeclarationName.cpp - Declaration names implementation -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -162,13 +161,7 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { return; case DeclarationName::CXXOperatorName: { - static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - nullptr, -#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - const char *OpName = OperatorNames[getCXXOverloadedOperator()]; + const char *OpName = getOperatorSpelling(getCXXOverloadedOperator()); assert(OpName && "not an overloaded operator"); OS << "operator"; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 7cdd3b2c2a30c..6ef77b8aee684 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1,9 +1,8 @@ //===--- Expr.cpp - Expression AST Node Implementation --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -11,13 +10,14 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Expr.h" +#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" -#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" @@ -229,6 +229,133 @@ SourceLocation Expr::getExprLoc() const { // Primary Expressions. //===----------------------------------------------------------------------===// +static void AssertResultStorageKind(ConstantExpr::ResultStorageKind Kind) { + assert((Kind == ConstantExpr::RSK_APValue || + Kind == ConstantExpr::RSK_Int64 || Kind == ConstantExpr::RSK_None) && + "Invalid StorageKind Value"); +} + +ConstantExpr::ResultStorageKind +ConstantExpr::getStorageKind(const APValue &Value) { + switch (Value.getKind()) { + case APValue::None: + case APValue::Indeterminate: + return ConstantExpr::RSK_None; + case APValue::Int: + if (!Value.getInt().needsCleanup()) + return ConstantExpr::RSK_Int64; + LLVM_FALLTHROUGH; + default: + return ConstantExpr::RSK_APValue; + } +} + +ConstantExpr::ResultStorageKind +ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) { + if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64) + return ConstantExpr::RSK_Int64; + return ConstantExpr::RSK_APValue; +} + +void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { + ConstantExprBits.ResultKind = StorageKind; + ConstantExprBits.APValueKind = APValue::None; + ConstantExprBits.HasCleanup = false; + if (StorageKind == ConstantExpr::RSK_APValue) + ::new (getTrailingObjects<APValue>()) APValue(); +} + +ConstantExpr::ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind) + : FullExpr(ConstantExprClass, subexpr) { + DefaultInit(StorageKind); +} + +ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, + ResultStorageKind StorageKind) { + assert(!isa<ConstantExpr>(E)); + AssertResultStorageKind(StorageKind); + unsigned Size = totalSizeToAlloc<APValue, uint64_t>( + StorageKind == ConstantExpr::RSK_APValue, + StorageKind == ConstantExpr::RSK_Int64); + void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); + ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind); + return Self; +} + +ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, + const APValue &Result) { + ResultStorageKind StorageKind = getStorageKind(Result); + ConstantExpr *Self = Create(Context, E, StorageKind); + Self->SetResult(Result, Context); + return Self; +} + +ConstantExpr::ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty) + : FullExpr(ConstantExprClass, Empty) { + DefaultInit(StorageKind); +} + +ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context, + ResultStorageKind StorageKind, + EmptyShell Empty) { + AssertResultStorageKind(StorageKind); + unsigned Size = totalSizeToAlloc<APValue, uint64_t>( + StorageKind == ConstantExpr::RSK_APValue, + StorageKind == ConstantExpr::RSK_Int64); + void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); + ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty); + return Self; +} + +void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) { + assert(getStorageKind(Value) == ConstantExprBits.ResultKind && + "Invalid storage for this value kind"); + ConstantExprBits.APValueKind = Value.getKind(); + switch (ConstantExprBits.ResultKind) { + case RSK_None: + return; + case RSK_Int64: + Int64Result() = *Value.getInt().getRawData(); + ConstantExprBits.BitWidth = Value.getInt().getBitWidth(); + ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned(); + return; + case RSK_APValue: + if (!ConstantExprBits.HasCleanup && Value.needsCleanup()) { + ConstantExprBits.HasCleanup = true; + Context.addDestruction(&APValueResult()); + } + APValueResult() = std::move(Value); + return; + } + llvm_unreachable("Invalid ResultKind Bits"); +} + +llvm::APSInt ConstantExpr::getResultAsAPSInt() const { + switch (ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_APValue: + return APValueResult().getInt(); + case ConstantExpr::RSK_Int64: + return llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), + ConstantExprBits.IsUnsigned); + default: + llvm_unreachable("invalid Accessor"); + } +} + +APValue ConstantExpr::getAPValueResult() const { + switch (ConstantExprBits.ResultKind) { + case ConstantExpr::RSK_APValue: + return APValueResult(); + case ConstantExpr::RSK_Int64: + return APValue( + llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), + ConstantExprBits.IsUnsigned)); + case ConstantExpr::RSK_None: + return APValue(); + } + llvm_unreachable("invalid ResultKind"); +} + /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. @@ -344,7 +471,8 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) { DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, - const DeclarationNameLoc &LocInfo) + const DeclarationNameLoc &LocInfo, + NonOdrUseReason NOUR) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), DNLoc(LocInfo) { DeclRefExprBits.HasQualifier = false; @@ -353,6 +481,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, DeclRefExprBits.HadMultipleCandidates = false; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; + DeclRefExprBits.NonOdrUseReason = NOUR; DeclRefExprBits.Loc = L; computeDependence(Ctx); } @@ -363,7 +492,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK) + QualType T, ExprValueKind VK, NonOdrUseReason NOUR) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), DNLoc(NameInfo.getInfo()) { DeclRefExprBits.Loc = NameInfo.getLoc(); @@ -384,6 +513,7 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; + DeclRefExprBits.NonOdrUseReason = NOUR; if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; @@ -405,30 +535,27 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - ValueDecl *D, + SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, - SourceLocation NameLoc, - QualType T, - ExprValueKind VK, - NamedDecl *FoundD, - const TemplateArgumentListInfo *TemplateArgs) { + SourceLocation NameLoc, QualType T, + ExprValueKind VK, NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs, + NonOdrUseReason NOUR) { return Create(Context, QualifierLoc, TemplateKWLoc, D, RefersToEnclosingVariableOrCapture, DeclarationNameInfo(D->getDeclName(), NameLoc), - T, VK, FoundD, TemplateArgs); + T, VK, FoundD, TemplateArgs, NOUR); } DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - ValueDecl *D, + SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, - QualType T, - ExprValueKind VK, + QualType T, ExprValueKind VK, NamedDecl *FoundD, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + NonOdrUseReason NOUR) { // Filter out cases where the found Decl is the same as the value refenenced. if (D == FoundD) FoundD = nullptr; @@ -443,8 +570,8 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, void *Mem = Context.Allocate(Size, alignof(DeclRefExpr)); return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D, - RefersToEnclosingVariableOrCapture, - NameInfo, FoundD, TemplateArgs, T, VK); + RefersToEnclosingVariableOrCapture, NameInfo, + FoundD, TemplateArgs, T, VK, NOUR); } DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, @@ -840,7 +967,7 @@ FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { - setRawSemantics(IEEEhalf); + setRawSemantics(llvm::APFloatBase::S_IEEEhalf); FloatingLiteralBits.IsExact = false; } @@ -855,41 +982,6 @@ FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } -const llvm::fltSemantics &FloatingLiteral::getSemantics() const { - switch(FloatingLiteralBits.Semantics) { - case IEEEhalf: - return llvm::APFloat::IEEEhalf(); - case IEEEsingle: - return llvm::APFloat::IEEEsingle(); - case IEEEdouble: - return llvm::APFloat::IEEEdouble(); - case x87DoubleExtended: - return llvm::APFloat::x87DoubleExtended(); - case IEEEquad: - return llvm::APFloat::IEEEquad(); - case PPCDoubleDouble: - return llvm::APFloat::PPCDoubleDouble(); - } - llvm_unreachable("Unrecognised floating semantics"); -} - -void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) { - if (&Sem == &llvm::APFloat::IEEEhalf()) - FloatingLiteralBits.Semantics = IEEEhalf; - else if (&Sem == &llvm::APFloat::IEEEsingle()) - FloatingLiteralBits.Semantics = IEEEsingle; - else if (&Sem == &llvm::APFloat::IEEEdouble()) - FloatingLiteralBits.Semantics = IEEEdouble; - else if (&Sem == &llvm::APFloat::x87DoubleExtended()) - FloatingLiteralBits.Semantics = x87DoubleExtended; - else if (&Sem == &llvm::APFloat::IEEEquad()) - FloatingLiteralBits.Semantics = IEEEquad; - else if (&Sem == &llvm::APFloat::PPCDoubleDouble()) - FloatingLiteralBits.Semantics = PPCDoubleDouble; - else - llvm_unreachable("Unknown floating semantics"); -} - /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. @@ -1359,6 +1451,8 @@ Decl *Expr::getReferencedDeclOfCallee() { return DRE->getDecl(); if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE)) return ME->getMemberDecl(); + if (auto *BE = dyn_cast<BlockExpr>(CEE)) + return BE->getBlockDecl(); return nullptr; } @@ -1536,29 +1630,46 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr( } } +MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, + ValueDecl *MemberDecl, + const DeclarationNameInfo &NameInfo, QualType T, + ExprValueKind VK, ExprObjectKind OK, + NonOdrUseReason NOUR) + : Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(), + Base->isValueDependent(), Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + Base(Base), MemberDecl(MemberDecl), MemberDNLoc(NameInfo.getInfo()), + MemberLoc(NameInfo.getLoc()) { + assert(!NameInfo.getName() || + MemberDecl->getDeclName() == NameInfo.getName()); + MemberExprBits.IsArrow = IsArrow; + MemberExprBits.HasQualifierOrFoundDecl = false; + MemberExprBits.HasTemplateKWAndArgsInfo = false; + MemberExprBits.HadMultipleCandidates = false; + MemberExprBits.NonOdrUseReason = NOUR; + MemberExprBits.OperatorLoc = OperatorLoc; +} + MemberExpr *MemberExpr::Create( - const ASTContext &C, Expr *base, bool isarrow, SourceLocation OperatorLoc, + const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - ValueDecl *memberdecl, DeclAccessPair founddecl, - DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs, - QualType ty, ExprValueKind vk, ExprObjectKind ok) { - - bool hasQualOrFound = (QualifierLoc || - founddecl.getDecl() != memberdecl || - founddecl.getAccess() != memberdecl->getAccess()); - - bool HasTemplateKWAndArgsInfo = targs || TemplateKWLoc.isValid(); + ValueDecl *MemberDecl, DeclAccessPair FoundDecl, + DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs, + QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) { + bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl || + FoundDecl.getAccess() != MemberDecl->getAccess(); + bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); std::size_t Size = totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo, - TemplateArgumentLoc>(hasQualOrFound ? 1 : 0, - HasTemplateKWAndArgsInfo ? 1 : 0, - targs ? targs->size() : 0); + TemplateArgumentLoc>( + HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0, + TemplateArgs ? TemplateArgs->size() : 0); void *Mem = C.Allocate(Size, alignof(MemberExpr)); - MemberExpr *E = new (Mem) - MemberExpr(base, isarrow, OperatorLoc, memberdecl, nameinfo, ty, vk, ok); + MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, + NameInfo, T, VK, OK, NOUR); - if (hasQualOrFound) { + if (HasQualOrFound) { // FIXME: Wrong. We should be looking at the member declaration we found. if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { E->setValueDependent(true); @@ -1574,19 +1685,20 @@ MemberExpr *MemberExpr::Create( MemberExprNameQualifier *NQ = E->getTrailingObjects<MemberExprNameQualifier>(); NQ->QualifierLoc = QualifierLoc; - NQ->FoundDecl = founddecl; + NQ->FoundDecl = FoundDecl; } E->MemberExprBits.HasTemplateKWAndArgsInfo = - (targs || TemplateKWLoc.isValid()); + TemplateArgs || TemplateKWLoc.isValid(); - if (targs) { + if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom( - TemplateKWLoc, *targs, E->getTrailingObjects<TemplateArgumentLoc>(), - Dependent, InstantiationDependent, ContainsUnexpandedParameterPack); + TemplateKWLoc, *TemplateArgs, + E->getTrailingObjects<TemplateArgumentLoc>(), Dependent, + InstantiationDependent, ContainsUnexpandedParameterPack); if (InstantiationDependent) E->setInstantiationDependent(true); } else if (TemplateKWLoc.isValid()) { @@ -1597,6 +1709,22 @@ MemberExpr *MemberExpr::Create( return E; } +MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context, + bool HasQualifier, bool HasFoundDecl, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs) { + assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) && + "template args but no template arg info?"); + bool HasQualOrFound = HasQualifier || HasFoundDecl; + std::size_t Size = + totalSizeToAlloc<MemberExprNameQualifier, ASTTemplateKWAndArgsInfo, + TemplateArgumentLoc>(HasQualOrFound ? 1 : 0, + HasTemplateKWAndArgsInfo ? 1 : 0, + NumTemplateArgs); + void *Mem = Context.Allocate(Size, alignof(MemberExpr)); + return new (Mem) MemberExpr(EmptyShell()); +} + SourceLocation MemberExpr::getBeginLoc() const { if (isImplicitAccess()) { if (hasQualifier()) @@ -1677,7 +1805,7 @@ bool CastExpr::CastConsistency() const { auto Ty = getType(); auto SETy = getSubExpr()->getType(); assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy)); - if (isRValue()) { + if (/*isRValue()*/ !Ty->getPointeeType().isNull()) { Ty = Ty->getPointeeType(); SETy = SETy->getPointeeType(); } @@ -1717,6 +1845,8 @@ bool CastExpr::CastConsistency() const { case CK_ZeroToOCLOpaqueType: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_FixedPointToIntegral: + case CK_IntegralToFixedPoint: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; @@ -1732,6 +1862,7 @@ bool CastExpr::CastConsistency() const { case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: case CK_LValueBitCast: // -> bool& + case CK_LValueToRValueBitCast: case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: case CK_FixedPointToBoolean: @@ -1847,6 +1978,11 @@ ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize)); + // Per C++ [conv.lval]p3, lvalue-to-rvalue conversions on class and + // std::nullptr_t have special semantics not captured by CK_LValueToRValue. + assert((Kind != CK_LValueToRValue || + !(T->isNullPtrType() || T->getAsCXXRecordDecl())) && + "invalid type for lvalue-to-rvalue conversion"); ImplicitCastExpr *E = new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK); if (PathSize) @@ -1989,6 +2125,91 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx, return true; } + +static QualType getDecayedSourceLocExprType(const ASTContext &Ctx, + SourceLocExpr::IdentKind Kind) { + switch (Kind) { + case SourceLocExpr::File: + case SourceLocExpr::Function: { + QualType ArrTy = Ctx.getStringLiteralArrayType(Ctx.CharTy, 0); + return Ctx.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType()); + } + case SourceLocExpr::Line: + case SourceLocExpr::Column: + return Ctx.UnsignedIntTy; + } + llvm_unreachable("unhandled case"); +} + +SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind, + SourceLocation BLoc, SourceLocation RParenLoc, + DeclContext *ParentContext) + : Expr(SourceLocExprClass, getDecayedSourceLocExprType(Ctx, Kind), + VK_RValue, OK_Ordinary, false, false, false, false), + BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) { + SourceLocExprBits.Kind = Kind; +} + +StringRef SourceLocExpr::getBuiltinStr() const { + switch (getIdentKind()) { + case File: + return "__builtin_FILE"; + case Function: + return "__builtin_FUNCTION"; + case Line: + return "__builtin_LINE"; + case Column: + return "__builtin_COLUMN"; + } + llvm_unreachable("unexpected IdentKind!"); +} + +APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx, + const Expr *DefaultExpr) const { + SourceLocation Loc; + const DeclContext *Context; + + std::tie(Loc, + Context) = [&]() -> std::pair<SourceLocation, const DeclContext *> { + if (auto *DIE = dyn_cast_or_null<CXXDefaultInitExpr>(DefaultExpr)) + return {DIE->getUsedLocation(), DIE->getUsedContext()}; + if (auto *DAE = dyn_cast_or_null<CXXDefaultArgExpr>(DefaultExpr)) + return {DAE->getUsedLocation(), DAE->getUsedContext()}; + return {this->getLocation(), this->getParentContext()}; + }(); + + PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc( + Ctx.getSourceManager().getExpansionRange(Loc).getEnd()); + + auto MakeStringLiteral = [&](StringRef Tmp) { + using LValuePathEntry = APValue::LValuePathEntry; + StringLiteral *Res = Ctx.getPredefinedStringLiteralFromCache(Tmp); + // Decay the string to a pointer to the first character. + LValuePathEntry Path[1] = {LValuePathEntry::ArrayIndex(0)}; + return APValue(Res, CharUnits::Zero(), Path, /*OnePastTheEnd=*/false); + }; + + switch (getIdentKind()) { + case SourceLocExpr::File: + return MakeStringLiteral(PLoc.getFilename()); + case SourceLocExpr::Function: { + const Decl *CurDecl = dyn_cast_or_null<Decl>(Context); + return MakeStringLiteral( + CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl) + : std::string("")); + } + case SourceLocExpr::Line: + case SourceLocExpr::Column: { + llvm::APSInt IntVal(Ctx.getIntWidth(Ctx.UnsignedIntTy), + /*isUnsigned=*/true); + IntVal = getIdentKind() == SourceLocExpr::Line ? PLoc.getLine() + : PLoc.getColumn(); + return APValue(IntVal); + } + } + llvm_unreachable("unhandled case"); +} + InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, @@ -2082,11 +2303,11 @@ bool InitListExpr::isTransparent() const { bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const { assert(isSyntacticForm() && "only test syntactic form as zero initializer"); - if (LangOpts.CPlusPlus || getNumInits() != 1) { + if (LangOpts.CPlusPlus || getNumInits() != 1 || !getInit(0)) { return false; } - const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0)); + const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(getInit(0)->IgnoreImplicit()); return Lit && Lit->getValue() == 0; } @@ -2256,12 +2477,13 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, // If only one of the LHS or RHS is a warning, the operator might // be being used for control flow. Only warn if both the LHS and // RHS are warnings. - const ConditionalOperator *Exp = cast<ConditionalOperator>(this); - if (!Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)) - return false; - if (!Exp->getLHS()) - return true; - return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + const auto *Exp = cast<ConditionalOperator>(this); + return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) && + Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + } + case BinaryConditionalOperatorClass: { + const auto *Exp = cast<BinaryConditionalOperator>(this); + return Exp->getFalseExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } case MemberExprClass: @@ -2557,205 +2779,197 @@ QualType Expr::findBoundMemberType(const Expr *expr) { return QualType(); } -Expr* Expr::IgnoreParens() { - Expr* E = this; - while (true) { - if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } - if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) { - if (!P->isConditionDependent()) { - E = P->getChosenSubExpr(); - continue; - } - } - if (ConstantExpr *CE = dyn_cast<ConstantExpr>(E)) { - E = CE->getSubExpr(); - continue; - } - return E; - } +static Expr *IgnoreImpCastsSingleStep(Expr *E) { + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + return ICE->getSubExpr(); + + if (auto *FE = dyn_cast<FullExpr>(E)) + return FE->getSubExpr(); + + return E; } -/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr -/// or CastExprs or ImplicitCastExprs, returning their operand. -Expr *Expr::IgnoreParenCasts() { - Expr *E = this; - while (true) { - E = E->IgnoreParens(); - if (CastExpr *P = dyn_cast<CastExpr>(E)) { - E = P->getSubExpr(); - continue; - } - if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = Materialize->GetTemporaryExpr(); - continue; - } - if (SubstNonTypeTemplateParmExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { - E = NTTP->getReplacement(); - continue; - } - if (FullExpr *FE = dyn_cast<FullExpr>(E)) { - E = FE->getSubExpr(); - continue; - } - return E; - } +static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) { + // FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in + // addition to what IgnoreImpCasts() skips to account for the current + // behaviour of IgnoreParenImpCasts(). + Expr *SubE = IgnoreImpCastsSingleStep(E); + if (SubE != E) + return SubE; + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->GetTemporaryExpr(); + + if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + + return E; } -Expr *Expr::IgnoreCasts() { - Expr *E = this; - while (true) { - if (CastExpr *P = dyn_cast<CastExpr>(E)) { - E = P->getSubExpr(); - continue; - } - if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = Materialize->GetTemporaryExpr(); - continue; - } - if (SubstNonTypeTemplateParmExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { - E = NTTP->getReplacement(); - continue; - } - if (FullExpr *FE = dyn_cast<FullExpr>(E)) { - E = FE->getSubExpr(); - continue; - } - return E; +static Expr *IgnoreCastsSingleStep(Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) + return CE->getSubExpr(); + + if (auto *FE = dyn_cast<FullExpr>(E)) + return FE->getSubExpr(); + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->GetTemporaryExpr(); + + if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + + return E; +} + +static Expr *IgnoreLValueCastsSingleStep(Expr *E) { + // Skip what IgnoreCastsSingleStep skips, except that only + // lvalue-to-rvalue casts are skipped. + if (auto *CE = dyn_cast<CastExpr>(E)) + if (CE->getCastKind() != CK_LValueToRValue) + return E; + + return IgnoreCastsSingleStep(E); +} + +static Expr *IgnoreBaseCastsSingleStep(Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) + if (CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) + return CE->getSubExpr(); + + return E; +} + +static Expr *IgnoreImplicitSingleStep(Expr *E) { + Expr *SubE = IgnoreImpCastsSingleStep(E); + if (SubE != E) + return SubE; + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->GetTemporaryExpr(); + + if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) + return BTE->getSubExpr(); + + return E; +} + +static Expr *IgnoreParensSingleStep(Expr *E) { + if (auto *PE = dyn_cast<ParenExpr>(E)) + return PE->getSubExpr(); + + if (auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Extension) + return UO->getSubExpr(); + } + + else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) { + if (!GSE->isResultDependent()) + return GSE->getResultExpr(); } + + else if (auto *CE = dyn_cast<ChooseExpr>(E)) { + if (!CE->isConditionDependent()) + return CE->getChosenSubExpr(); + } + + else if (auto *CE = dyn_cast<ConstantExpr>(E)) + return CE->getSubExpr(); + + return E; } -/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue -/// casts. This is intended purely as a temporary workaround for code -/// that hasn't yet been rewritten to do the right thing about those -/// casts, and may disappear along with the last internal use. -Expr *Expr::IgnoreParenLValueCasts() { - Expr *E = this; - while (true) { - E = E->IgnoreParens(); - if (CastExpr *P = dyn_cast<CastExpr>(E)) { - if (P->getCastKind() == CK_LValueToRValue) { - E = P->getSubExpr(); - continue; - } - } else if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = Materialize->GetTemporaryExpr(); - continue; - } else if (SubstNonTypeTemplateParmExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { - E = NTTP->getReplacement(); - continue; - } else if (FullExpr *FE = dyn_cast<FullExpr>(E)) { - E = FE->getSubExpr(); - continue; - } - break; +static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) { + // We ignore integer <-> casts that are of the same width, ptr<->ptr and + // ptr<->int casts of the same width. We also ignore all identity casts. + Expr *SubExpr = CE->getSubExpr(); + bool IsIdentityCast = + Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType()); + bool IsSameWidthCast = + (E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) && + (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isIntegralType(Ctx)) && + (Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType())); + + if (IsIdentityCast || IsSameWidthCast) + return SubExpr; } + + else if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + return E; } -Expr *Expr::ignoreParenBaseCasts() { - Expr *E = this; - while (true) { - E = E->IgnoreParens(); - if (CastExpr *CE = dyn_cast<CastExpr>(E)) { - if (CE->getCastKind() == CK_DerivedToBase || - CE->getCastKind() == CK_UncheckedDerivedToBase || - CE->getCastKind() == CK_NoOp) { - E = CE->getSubExpr(); - continue; - } - } +static Expr *IgnoreExprNodesImpl(Expr *E) { return E; } +template <typename FnTy, typename... FnTys> +static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) { + return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...); +} - return E; +/// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *, +/// Recursively apply each of the functions to E until reaching a fixed point. +/// Note that a null E is valid; in this case nothing is done. +template <typename... FnTys> +static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) { + Expr *LastE = nullptr; + while (E != LastE) { + LastE = E; + E = IgnoreExprNodesImpl(E, std::forward<FnTys>(Fns)...); } + return E; +} + +Expr *Expr::IgnoreImpCasts() { + return IgnoreExprNodes(this, IgnoreImpCastsSingleStep); +} + +Expr *Expr::IgnoreCasts() { + return IgnoreExprNodes(this, IgnoreCastsSingleStep); +} + +Expr *Expr::IgnoreImplicit() { + return IgnoreExprNodes(this, IgnoreImplicitSingleStep); +} + +Expr *Expr::IgnoreParens() { + return IgnoreExprNodes(this, IgnoreParensSingleStep); } Expr *Expr::IgnoreParenImpCasts() { - Expr *E = this; - while (true) { - E = E->IgnoreParens(); - if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) { - E = P->getSubExpr(); - continue; - } - if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = Materialize->GetTemporaryExpr(); - continue; - } - if (SubstNonTypeTemplateParmExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { - E = NTTP->getReplacement(); - continue; - } - return E; - } + return IgnoreExprNodes(this, IgnoreParensSingleStep, + IgnoreImpCastsExtraSingleStep); +} + +Expr *Expr::IgnoreParenCasts() { + return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreCastsSingleStep); } Expr *Expr::IgnoreConversionOperator() { - if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) { + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(this)) { if (MCE->getMethodDecl() && isa<CXXConversionDecl>(MCE->getMethodDecl())) return MCE->getImplicitObjectArgument(); } return this; } -/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the -/// value (including ptr->int casts of the same size). Strip off any -/// ParenExpr or CastExprs, returning their operand. -Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { - Expr *E = this; - while (true) { - E = E->IgnoreParens(); - - if (CastExpr *P = dyn_cast<CastExpr>(E)) { - // We ignore integer <-> casts that are of the same width, ptr<->ptr and - // ptr<->int casts of the same width. We also ignore all identity casts. - Expr *SE = P->getSubExpr(); - - if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { - E = SE; - continue; - } - - if ((E->getType()->isPointerType() || - E->getType()->isIntegralType(Ctx)) && - (SE->getType()->isPointerType() || - SE->getType()->isIntegralType(Ctx)) && - Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { - E = SE; - continue; - } - } +Expr *Expr::IgnoreParenLValueCasts() { + return IgnoreExprNodes(this, IgnoreParensSingleStep, + IgnoreLValueCastsSingleStep); +} - if (SubstNonTypeTemplateParmExpr *NTTP - = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { - E = NTTP->getReplacement(); - continue; - } +Expr *Expr::ignoreParenBaseCasts() { + return IgnoreExprNodes(this, IgnoreParensSingleStep, + IgnoreBaseCastsSingleStep); +} - return E; - } +Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) { + return IgnoreExprNodes(this, IgnoreParensSingleStep, [&Ctx](Expr *E) { + return IgnoreNoopCastsSingleStep(Ctx, E); + }); } bool Expr::isDefaultArgument() const { @@ -2893,6 +3107,9 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) { bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, const Expr **Culprit) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + // This function is attempting whether an expression is an initializer // which can be evaluated at compile-time. It very closely parallels // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it @@ -2952,6 +3169,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, } case InitListExprClass: { const InitListExpr *ILE = cast<InitListExpr>(this); + assert(ILE->isSemanticForm() && "InitListExpr must be in semantic form"); if (ILE->getType()->isArrayType()) { unsigned numInits = ILE->getNumInits(); for (unsigned i = 0; i < numInits; i++) { @@ -3160,6 +3378,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ObjCAvailabilityCheckExprClass: case CXXUuidofExprClass: case OpaqueValueExprClass: + case SourceLocExprClass: // These never have a side-effect. return false; @@ -3288,7 +3507,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case CXXStaticCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: - case CXXFunctionalCastExprClass: { + case CXXFunctionalCastExprClass: + case BuiltinBitCastExprClass: { // While volatile reads are side-effecting in both C and C++, we treat them // as having possible (not definite) side-effects. This allows idiomatic // code to behave without warning, such as sizeof(*v) for a volatile- @@ -3775,55 +3995,95 @@ void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) { memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size()); } -GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, - SourceLocation GenericLoc, Expr *ControllingExpr, - ArrayRef<TypeSourceInfo*> AssocTypes, - ArrayRef<Expr*> AssocExprs, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - bool ContainsUnexpandedParameterPack, - unsigned ResultIndex) - : Expr(GenericSelectionExprClass, - AssocExprs[ResultIndex]->getType(), - AssocExprs[ResultIndex]->getValueKind(), - AssocExprs[ResultIndex]->getObjectKind(), - AssocExprs[ResultIndex]->isTypeDependent(), - AssocExprs[ResultIndex]->isValueDependent(), - AssocExprs[ResultIndex]->isInstantiationDependent(), - ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), - SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), - NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex), - GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { - SubExprs[CONTROLLING] = ControllingExpr; - assert(AssocTypes.size() == AssocExprs.size()); - std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); - std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); -} - -GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, - SourceLocation GenericLoc, Expr *ControllingExpr, - ArrayRef<TypeSourceInfo*> AssocTypes, - ArrayRef<Expr*> AssocExprs, - SourceLocation DefaultLoc, - SourceLocation RParenLoc, - bool ContainsUnexpandedParameterPack) - : Expr(GenericSelectionExprClass, - Context.DependentTy, - VK_RValue, - OK_Ordinary, - /*isTypeDependent=*/true, - /*isValueDependent=*/true, - /*isInstantiationDependent=*/true, - ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), - SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), - NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc), - DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { - SubExprs[CONTROLLING] = ControllingExpr; - assert(AssocTypes.size() == AssocExprs.size()); - std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); - std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); +GenericSelectionExpr::GenericSelectionExpr( + const ASTContext &, SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, unsigned ResultIndex) + : Expr(GenericSelectionExprClass, AssocExprs[ResultIndex]->getType(), + AssocExprs[ResultIndex]->getValueKind(), + AssocExprs[ResultIndex]->getObjectKind(), + AssocExprs[ResultIndex]->isTypeDependent(), + AssocExprs[ResultIndex]->isValueDependent(), + AssocExprs[ResultIndex]->isInstantiationDependent(), + ContainsUnexpandedParameterPack), + NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex), + DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { + assert(AssocTypes.size() == AssocExprs.size() && + "Must have the same number of association expressions" + " and TypeSourceInfo!"); + assert(ResultIndex < NumAssocs && "ResultIndex is out-of-bounds!"); + + GenericSelectionExprBits.GenericLoc = GenericLoc; + getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr; + std::copy(AssocExprs.begin(), AssocExprs.end(), + getTrailingObjects<Stmt *>() + AssocExprStartIndex); + std::copy(AssocTypes.begin(), AssocTypes.end(), + getTrailingObjects<TypeSourceInfo *>()); +} + +GenericSelectionExpr::GenericSelectionExpr( + const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack) + : Expr(GenericSelectionExprClass, Context.DependentTy, VK_RValue, + OK_Ordinary, + /*isTypeDependent=*/true, + /*isValueDependent=*/true, + /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack), + NumAssocs(AssocExprs.size()), ResultIndex(ResultDependentIndex), + DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { + assert(AssocTypes.size() == AssocExprs.size() && + "Must have the same number of association expressions" + " and TypeSourceInfo!"); + + GenericSelectionExprBits.GenericLoc = GenericLoc; + getTrailingObjects<Stmt *>()[ControllingIndex] = ControllingExpr; + std::copy(AssocExprs.begin(), AssocExprs.end(), + getTrailingObjects<Stmt *>() + AssocExprStartIndex); + std::copy(AssocTypes.begin(), AssocTypes.end(), + getTrailingObjects<TypeSourceInfo *>()); +} + +GenericSelectionExpr::GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs) + : Expr(GenericSelectionExprClass, Empty), NumAssocs(NumAssocs) {} + +GenericSelectionExpr *GenericSelectionExpr::Create( + const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, unsigned ResultIndex) { + unsigned NumAssocs = AssocExprs.size(); + void *Mem = Context.Allocate( + totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs), + alignof(GenericSelectionExpr)); + return new (Mem) GenericSelectionExpr( + Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc, + RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); +} + +GenericSelectionExpr *GenericSelectionExpr::Create( + const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, + ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack) { + unsigned NumAssocs = AssocExprs.size(); + void *Mem = Context.Allocate( + totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs), + alignof(GenericSelectionExpr)); + return new (Mem) GenericSelectionExpr( + Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc, + RParenLoc, ContainsUnexpandedParameterPack); +} + +GenericSelectionExpr * +GenericSelectionExpr::CreateEmpty(const ASTContext &Context, + unsigned NumAssocs) { + void *Mem = Context.Allocate( + totalSizeToAlloc<Stmt *, TypeSourceInfo *>(1 + NumAssocs, NumAssocs), + alignof(GenericSelectionExpr)); + return new (Mem) GenericSelectionExpr(EmptyShell(), NumAssocs); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3891f45c7fc2c..b30f785ba8f54 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -1,9 +1,8 @@ //===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -98,7 +97,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete, bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens, - Expr *ArraySize, InitializationStyle InitializationStyle, + Optional<Expr *> ArraySize, + InitializationStyle InitializationStyle, Expr *Initializer, QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, SourceRange DirectInitRange) @@ -113,7 +113,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, "Only NoInit can have no initializer!"); CXXNewExprBits.IsGlobalNew = IsGlobalNew; - CXXNewExprBits.IsArray = ArraySize != nullptr; + CXXNewExprBits.IsArray = ArraySize.hasValue(); CXXNewExprBits.ShouldPassAlignment = ShouldPassAlignment; CXXNewExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize; CXXNewExprBits.StoredInitializationStyle = @@ -123,12 +123,14 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew, CXXNewExprBits.NumPlacementArgs = PlacementArgs.size(); if (ArraySize) { - if (ArraySize->isInstantiationDependent()) - ExprBits.InstantiationDependent = true; - if (ArraySize->containsUnexpandedParameterPack()) - ExprBits.ContainsUnexpandedParameterPack = true; + if (Expr *SizeExpr = *ArraySize) { + if (SizeExpr->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; + if (SizeExpr->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + } - getTrailingObjects<Stmt *>()[arraySizeOffset()] = ArraySize; + getTrailingObjects<Stmt *>()[arraySizeOffset()] = *ArraySize; } if (Initializer) { @@ -180,11 +182,11 @@ CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew, FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete, bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens, - Expr *ArraySize, InitializationStyle InitializationStyle, - Expr *Initializer, QualType Ty, - TypeSourceInfo *AllocatedTypeInfo, SourceRange Range, - SourceRange DirectInitRange) { - bool IsArray = ArraySize != nullptr; + Optional<Expr *> ArraySize, + InitializationStyle InitializationStyle, Expr *Initializer, + QualType Ty, TypeSourceInfo *AllocatedTypeInfo, + SourceRange Range, SourceRange DirectInitRange) { + bool IsArray = ArraySize.hasValue(); bool HasInit = Initializer != nullptr; unsigned NumPlacementArgs = PlacementArgs.size(); bool IsParenTypeId = TypeIdParens.isValid(); @@ -905,13 +907,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const { } CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx, SourceLocation Loc, - FieldDecl *Field, QualType Ty) + FieldDecl *Field, QualType Ty, + DeclContext *UsedContext) : Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx), Ty->isLValueReferenceType() ? VK_LValue : Ty->isRValueReferenceType() ? VK_XValue : VK_RValue, /*FIXME*/ OK_Ordinary, false, false, false, false), - Field(Field) { + Field(Field), UsedContext(UsedContext) { CXXDefaultInitExprBits.Loc = Loc; assert(Field->hasInClassInitializer()); } @@ -1205,7 +1208,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const { TemplateParameterList *LambdaExpr::getTemplateParameterList() const { CXXRecordDecl *Record = getLambdaClass(); return Record->getGenericLambdaTemplateParameterList(); +} +ArrayRef<NamedDecl *> LambdaExpr::getExplicitTemplateParameters() const { + const CXXRecordDecl *Record = getLambdaClass(); + return Record->getLambdaExplicitTemplateParameters(); } CompoundStmt *LambdaExpr::getBody() const { @@ -1534,30 +1541,30 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments)); } -FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, +FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack, SourceLocation NameLoc, unsigned NumParams, - ParmVarDecl *const *Params) + VarDecl *const *Params) : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, true, true, true, true), ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { if (Params) std::uninitialized_copy(Params, Params + NumParams, - getTrailingObjects<ParmVarDecl *>()); + getTrailingObjects<VarDecl *>()); } FunctionParmPackExpr * FunctionParmPackExpr::Create(const ASTContext &Context, QualType T, - ParmVarDecl *ParamPack, SourceLocation NameLoc, - ArrayRef<ParmVarDecl *> Params) { - return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(Params.size()))) + VarDecl *ParamPack, SourceLocation NameLoc, + ArrayRef<VarDecl *> Params) { + return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(Params.size()))) FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); } FunctionParmPackExpr * FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, unsigned NumParams) { - return new (Context.Allocate(totalSizeToAlloc<ParmVarDecl *>(NumParams))) + return new (Context.Allocate(totalSizeToAlloc<VarDecl *>(NumParams))) FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr); } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index e1d6a1c9edcc8..c61ee703aca8e 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -1,9 +1,8 @@ //===- ExprClassification.cpp - Expression AST Node Implementation --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -192,6 +191,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: + case Expr::SourceLocExprClass: return Cl::CL_PRValue; case Expr::ConstantExprClass: @@ -343,6 +343,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: + case Expr::BuiltinBitCastExprClass: // Only in C++ can casts be interesting at all. if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index da093ff22c123..f01b42e7ff761 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1,9 +1,8 @@ //===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -38,13 +37,18 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/CurrentSourceLocExprScope.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/OSLog.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include <cstring> @@ -53,8 +57,10 @@ #define DEBUG_TYPE "exprconstant" using namespace clang; +using llvm::APInt; using llvm::APSInt; using llvm::APFloat; +using llvm::Optional; static bool IsGlobalLValue(APValue::LValueBase B); @@ -63,6 +69,9 @@ namespace { struct CallStackFrame; struct EvalInfo; + using SourceLocExprScopeGuard = + CurrentSourceLocExprScope::SourceLocExprScopeGuard; + static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { @@ -82,6 +91,9 @@ namespace { return D->getType(); } + if (B.is<TypeInfoLValue>()) + return B.getTypeInfoType(); + const Expr *Base = B.get<const Expr*>(); // For a materialized temporary, the type of the temporary we materialized @@ -103,28 +115,19 @@ namespace { } /// Get an LValue path entry, which is known to not be an array index, as a - /// field or base class. - static - APValue::BaseOrMemberType getAsBaseOrMember(APValue::LValuePathEntry E) { - APValue::BaseOrMemberType Value; - Value.setFromOpaqueValue(E.BaseOrMember); - return Value; - } - - /// Get an LValue path entry, which is known to not be an array index, as a /// field declaration. static const FieldDecl *getAsField(APValue::LValuePathEntry E) { - return dyn_cast<FieldDecl>(getAsBaseOrMember(E).getPointer()); + return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer()); } /// Get an LValue path entry, which is known to not be an array index, as a /// base class declaration. static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) { - return dyn_cast<CXXRecordDecl>(getAsBaseOrMember(E).getPointer()); + return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer()); } /// Determine whether this LValue path entry for a base class names a virtual /// base class. static bool isVirtualBaseClass(APValue::LValuePathEntry E) { - return getAsBaseOrMember(E).getInt(); + return E.getAsBaseOrMember().getInt(); } /// Given a CallExpr, try to get the alloc_size attribute. May return null. @@ -222,7 +225,7 @@ namespace { // The order of this enum is important for diagnostics. enum CheckSubobjectKind { CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex, - CSK_This, CSK_Real, CSK_Imag + CSK_Real, CSK_Imag }; /// A path from a glvalue to a subobject of that glvalue. @@ -291,6 +294,27 @@ namespace { } } + void truncate(ASTContext &Ctx, APValue::LValueBase Base, + unsigned NewLength) { + if (Invalid) + return; + + assert(Base && "cannot truncate path for null pointer"); + assert(NewLength <= Entries.size() && "not a truncation"); + + if (NewLength == Entries.size()) + return; + Entries.resize(NewLength); + + bool IsArray = false; + bool FirstIsUnsizedArray = false; + MostDerivedPathLength = findMostDerivedSubobject( + Ctx, Base, Entries, MostDerivedArraySize, MostDerivedType, IsArray, + FirstIsUnsizedArray); + MostDerivedIsArrayElement = IsArray; + FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray; + } + void setInvalid() { Invalid = true; Entries.clear(); @@ -316,7 +340,8 @@ namespace { if (IsOnePastTheEnd) return true; if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement && - Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize) + Entries[MostDerivedPathLength - 1].getAsArrayIndex() == + MostDerivedArraySize) return true; return false; } @@ -333,8 +358,8 @@ namespace { // an array of length one with the type of the object as its element type. bool IsArray = MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement; - uint64_t ArrayIndex = - IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; + uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex() + : (uint64_t)IsOnePastTheEnd; uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1; return {ArrayIndex, ArraySize - ArrayIndex}; @@ -360,9 +385,7 @@ namespace { /// Update this designator to refer to the first element within this array. void addArrayUnchecked(const ConstantArrayType *CAT) { - PathEntry Entry; - Entry.ArrayIndex = 0; - Entries.push_back(Entry); + Entries.push_back(PathEntry::ArrayIndex(0)); // This is a most-derived object. MostDerivedType = CAT->getElementType(); @@ -373,9 +396,7 @@ namespace { /// Update this designator to refer to the first element within the array of /// elements of type T. This is an array of unknown size. void addUnsizedArrayUnchecked(QualType ElemTy) { - PathEntry Entry; - Entry.ArrayIndex = 0; - Entries.push_back(Entry); + Entries.push_back(PathEntry::ArrayIndex(0)); MostDerivedType = ElemTy; MostDerivedIsArrayElement = true; @@ -388,10 +409,7 @@ namespace { /// Update this designator to refer to the given base or member of this /// object. void addDeclUnchecked(const Decl *D, bool Virtual = false) { - PathEntry Entry; - APValue::BaseOrMemberType Value(D, Virtual); - Entry.BaseOrMember = Value.getOpaqueValue(); - Entries.push_back(Entry); + Entries.push_back(APValue::BaseOrMemberType(D, Virtual)); // If this isn't a base class, it's a new most-derived object. if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) { @@ -403,9 +421,7 @@ namespace { } /// Update this designator to refer to the given complex component. void addComplexUnchecked(QualType EltTy, bool Imag) { - PathEntry Entry; - Entry.ArrayIndex = Imag; - Entries.push_back(Entry); + Entries.push_back(PathEntry::ArrayIndex(Imag)); // This is technically a most-derived object, though in practice this // is unlikely to matter. @@ -426,7 +442,8 @@ namespace { // Can't verify -- trust that the user is doing the right thing (or if // not, trust that the caller will catch the bad behavior). // FIXME: Should we reject if this overflows, at least? - Entries.back().ArrayIndex += TruncatedN; + Entries.back() = PathEntry::ArrayIndex( + Entries.back().getAsArrayIndex() + TruncatedN); return; } @@ -435,8 +452,8 @@ namespace { // an array of length one with the type of the object as its element type. bool IsArray = MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement; - uint64_t ArrayIndex = - IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd; + uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex() + : (uint64_t)IsOnePastTheEnd; uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1; @@ -456,7 +473,7 @@ namespace { "bounds check succeeded for out-of-bounds index"); if (IsArray) - Entries.back().ArrayIndex = ArrayIndex; + Entries.back() = PathEntry::ArrayIndex(ArrayIndex); else IsOnePastTheEnd = (ArrayIndex != 0); } @@ -479,6 +496,10 @@ namespace { /// parameters' function scope indices. APValue *Arguments; + /// Source location information about the default argument or default + /// initializer expression we're evaluating, if any. + CurrentSourceLocExprScope CurSourceLocExprScope; + // Note that we intentionally use std::map here so that references to // values are stable. typedef std::pair<const void *, unsigned> MapKeyTy; @@ -613,6 +634,15 @@ namespace { } return *this; } + + OptionalDiagnostic &operator<<(const APFixedPoint &FX) { + if (Diag) { + SmallVector<char, 32> Buffer; + FX.toString(Buffer); + *Diag << StringRef(Buffer.data(), Buffer.size()); + } + return *this; + } }; /// A cleanup, and a flag indicating whether it is lifetime-extended. @@ -629,6 +659,40 @@ namespace { } }; + /// A reference to an object whose construction we are currently evaluating. + struct ObjectUnderConstruction { + APValue::LValueBase Base; + ArrayRef<APValue::LValuePathEntry> Path; + friend bool operator==(const ObjectUnderConstruction &LHS, + const ObjectUnderConstruction &RHS) { + return LHS.Base == RHS.Base && LHS.Path == RHS.Path; + } + friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) { + return llvm::hash_combine(Obj.Base, Obj.Path); + } + }; + enum class ConstructionPhase { None, Bases, AfterBases }; +} + +namespace llvm { +template<> struct DenseMapInfo<ObjectUnderConstruction> { + using Base = DenseMapInfo<APValue::LValueBase>; + static ObjectUnderConstruction getEmptyKey() { + return {Base::getEmptyKey(), {}}; } + static ObjectUnderConstruction getTombstoneKey() { + return {Base::getTombstoneKey(), {}}; + } + static unsigned getHashValue(const ObjectUnderConstruction &Object) { + return hash_value(Object); + } + static bool isEqual(const ObjectUnderConstruction &LHS, + const ObjectUnderConstruction &RHS) { + return LHS == RHS; + } +}; +} + +namespace { /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information /// about the AST context, but also maintains information about the folded @@ -679,34 +743,41 @@ namespace { /// declaration whose initializer is being evaluated, if any. APValue *EvaluatingDeclValue; - /// EvaluatingObject - Pair of the AST node that an lvalue represents and - /// the call index that that lvalue was allocated in. - typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>> - EvaluatingObject; - - /// EvaluatingConstructors - Set of objects that are currently being - /// constructed. - llvm::DenseSet<EvaluatingObject> EvaluatingConstructors; + /// Set of objects that are currently being constructed. + llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase> + ObjectsUnderConstruction; struct EvaluatingConstructorRAII { EvalInfo &EI; - EvaluatingObject Object; + ObjectUnderConstruction Object; bool DidInsert; - EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object) + EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object, + bool HasBases) : EI(EI), Object(Object) { - DidInsert = EI.EvaluatingConstructors.insert(Object).second; + DidInsert = + EI.ObjectsUnderConstruction + .insert({Object, HasBases ? ConstructionPhase::Bases + : ConstructionPhase::AfterBases}) + .second; + } + void finishedConstructingBases() { + EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases; } ~EvaluatingConstructorRAII() { - if (DidInsert) EI.EvaluatingConstructors.erase(Object); + if (DidInsert) EI.ObjectsUnderConstruction.erase(Object); } }; - bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex, - unsigned Version) { - return EvaluatingConstructors.count( - EvaluatingObject(Decl, {CallIndex, Version})); + ConstructionPhase + isEvaluatingConstructor(APValue::LValueBase Base, + ArrayRef<APValue::LValuePathEntry> Path) { + return ObjectsUnderConstruction.lookup({Base, Path}); } + /// If we're currently speculatively evaluating, the outermost call stack + /// depth at which we can mutate state, otherwise 0. + unsigned SpeculativeEvaluationDepth = 0; + /// The current array initialization index, if we're performing array /// initialization. uint64_t ArrayInitIndex = -1; @@ -719,9 +790,6 @@ namespace { /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; - /// Whether or not we're currently speculatively evaluating. - bool IsSpeculativelyEvaluating; - /// Whether or not we're in a context where the front end requires a /// constant value. bool InConstantContext; @@ -786,13 +854,12 @@ namespace { BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), EvaluatingDecl((const ValueDecl *)nullptr), EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), - HasFoldFailureDiagnostic(false), IsSpeculativelyEvaluating(false), + HasFoldFailureDiagnostic(false), InConstantContext(false), EvalMode(Mode) {} void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; - EvaluatingConstructors.insert({Base, {0, 0}}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -814,14 +881,20 @@ namespace { return false; } - CallStackFrame *getCallFrame(unsigned CallIndex) { - assert(CallIndex && "no call index in getCallFrame"); + std::pair<CallStackFrame *, unsigned> + getCallFrameAndDepth(unsigned CallIndex) { + assert(CallIndex && "no call index in getCallFrameAndDepth"); // We will eventually hit BottomFrame, which has Index 1, so Frame can't // be null in this loop. + unsigned Depth = CallStackDepth; CallStackFrame *Frame = CurrentCall; - while (Frame->Index > CallIndex) + while (Frame->Index > CallIndex) { Frame = Frame->Caller; - return (Frame->Index == CallIndex) ? Frame : nullptr; + --Depth; + } + if (Frame->Index == CallIndex) + return {Frame, Depth}; + return {nullptr, 0}; } bool nextStep(const Stmt *S) { @@ -1102,12 +1175,12 @@ namespace { class SpeculativeEvaluationRAII { EvalInfo *Info = nullptr; Expr::EvalStatus OldStatus; - bool OldIsSpeculativelyEvaluating; + unsigned OldSpeculativeEvaluationDepth; void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) { Info = Other.Info; OldStatus = Other.OldStatus; - OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating; + OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth; Other.Info = nullptr; } @@ -1116,7 +1189,7 @@ namespace { return; Info->EvalStatus = OldStatus; - Info->IsSpeculativelyEvaluating = OldIsSpeculativelyEvaluating; + Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth; } public: @@ -1125,9 +1198,9 @@ namespace { SpeculativeEvaluationRAII( EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr) : Info(&Info), OldStatus(Info.EvalStatus), - OldIsSpeculativelyEvaluating(Info.IsSpeculativelyEvaluating) { + OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) { Info.EvalStatus.Diag = NewDiag; - Info.IsSpeculativelyEvaluating = true; + Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1; } SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete; @@ -1243,7 +1316,7 @@ APValue &CallStackFrame::createTemporary(const void *Key, bool IsLifetimeExtended) { unsigned Version = Info.CurrentCall->getTempVersion(); APValue &Result = Temporaries[MapKeyTy(Key, Version)]; - assert(Result.isUninit() && "temporary created multiple times"); + assert(Result.isAbsent() && "temporary created multiple times"); Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); return Result; } @@ -1290,14 +1363,40 @@ void EvalInfo::addCallStack(unsigned Limit) { } } -/// Kinds of access we can perform on an object, for diagnostics. +/// Kinds of access we can perform on an object, for diagnostics. Note that +/// we consider a member function call to be a kind of access, even though +/// it is not formally an access of the object, because it has (largely) the +/// same set of semantic restrictions. enum AccessKinds { AK_Read, AK_Assign, AK_Increment, - AK_Decrement + AK_Decrement, + AK_MemberCall, + AK_DynamicCast, + AK_TypeId, }; +static bool isModification(AccessKinds AK) { + switch (AK) { + case AK_Read: + case AK_MemberCall: + case AK_DynamicCast: + case AK_TypeId: + return false; + case AK_Assign: + case AK_Increment: + case AK_Decrement: + return true; + } + llvm_unreachable("unknown access kind"); +} + +/// Is this an access per the C++ definition? +static bool isFormalAccess(AccessKinds AK) { + return AK == AK_Read || isModification(AK); +} + namespace { struct ComplexValue { private: @@ -1613,6 +1712,14 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, EvalInfo &Info); static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); +/// Evaluate an integer or fixed point expression into an APResult. +static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, + EvalInfo &Info); + +/// Evaluate only a fixed point expression into an APResult. +static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result, + EvalInfo &Info); + //===----------------------------------------------------------------------===// // Misc utilities //===----------------------------------------------------------------------===// @@ -1706,6 +1813,9 @@ static bool IsGlobalLValue(APValue::LValueBase B) { return isa<FunctionDecl>(D); } + if (B.is<TypeInfoLValue>()) + return true; + const Expr *E = B.get<const Expr*>(); switch (E->getStmtClass()) { default: @@ -1723,9 +1833,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) { case Expr::PredefinedExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: - case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: return true; + case Expr::ObjCBoxedExprClass: + return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer(); case Expr::CallExprClass: return IsStringLiteralCall(cast<CallExpr>(E)); // For GCC compatibility, &&label has static storage duration. @@ -1799,9 +1910,9 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); if (VD) Info.Note(VD->getLocation(), diag::note_declared_at); - else - Info.Note(Base.get<const Expr*>()->getExprLoc(), - diag::note_constexpr_temporary_here); + else if (const Expr *E = Base.dyn_cast<const Expr*>()) + Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here); + // We have no information to show for a typeid(T) object. } /// Check that this reference or pointer core constant expression is a valid @@ -1938,10 +2049,13 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value, - Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) { - if (Value.isUninit()) { + Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen, + SourceLocation SubobjectLoc = SourceLocation()) { + if (!Value.hasValue()) { Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) << true << Type; + if (SubobjectLoc.isValid()) + Info.Note(SubobjectLoc, diag::note_constexpr_subobject_declared_here); return false; } @@ -1957,18 +2071,20 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType(); for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) { if (!CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayInitializedElt(I), Usage)) + Value.getArrayInitializedElt(I), Usage, + SubobjectLoc)) return false; } if (!Value.hasArrayFiller()) return true; return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(), - Usage); + Usage, SubobjectLoc); } if (Value.isUnion() && Value.getUnionField()) { return CheckConstantExpression(Info, DiagLoc, Value.getUnionField()->getType(), - Value.getUnionValue(), Usage); + Value.getUnionValue(), Usage, + Value.getUnionField()->getLocation()); } if (Value.isStruct()) { RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); @@ -1976,7 +2092,8 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { if (!CheckConstantExpression(Info, DiagLoc, BS.getType(), - Value.getStructBase(BaseIndex), Usage)) + Value.getStructBase(BaseIndex), Usage, + BS.getBeginLoc())) return false; ++BaseIndex; } @@ -1987,7 +2104,7 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, if (!CheckConstantExpression(Info, DiagLoc, I->getType(), Value.getStructField(I->getFieldIndex()), - Usage)) + Usage, I->getLocation())) return false; } } @@ -2022,11 +2139,15 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { static bool HandleConversionToBool(const APValue &Val, bool &Result) { switch (Val.getKind()) { - case APValue::Uninitialized: + case APValue::None: + case APValue::Indeterminate: return false; case APValue::Int: Result = Val.getInt().getBoolValue(); return true; + case APValue::FixedPoint: + Result = Val.getFixedPoint().getBoolValue(); + return true; case APValue::Float: Result = !Val.getFloat().isZero(); return true; @@ -2091,10 +2212,8 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, APFloat &Result) { APFloat Value = Result; bool ignored; - if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), - APFloat::rmNearestTiesToEven, &ignored) - & APFloat::opOverflow) - return HandleOverflow(Info, E, Value, DestType); + Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), + APFloat::rmNearestTiesToEven, &ignored); return true; } @@ -2115,10 +2234,8 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, const APSInt &Value, QualType DestType, APFloat &Result) { Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1); - if (Result.convertFromAPInt(Value, Value.isSigned(), - APFloat::rmNearestTiesToEven) - & APFloat::opOverflow) - return HandleOverflow(Info, E, Value, DestType); + Result.convertFromAPInt(Value, Value.isSigned(), + APFloat::rmNearestTiesToEven); return true; } @@ -2270,9 +2387,11 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, if (SA != RHS) { Info.CCEDiag(E, diag::note_constexpr_large_shift) << RHS << E->getType() << LHS.getBitWidth(); - } else if (LHS.isSigned()) { + } else if (LHS.isSigned() && !Info.getLangOpts().CPlusPlus2a) { // C++11 [expr.shift]p2: A signed left shift must have a non-negative // operand, and must not overflow the corresponding unsigned type. + // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to + // E1 x 2^E2 module 2^N. if (LHS.isNegative()) Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; else if (LHS.countLeadingZeros() < SA) @@ -2334,11 +2453,19 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, LHS.subtract(RHS, APFloat::rmNearestTiesToEven); break; case BO_Div: + // [expr.mul]p4: + // If the second operand of / or % is zero the behavior is undefined. + if (RHS.isZero()) + Info.CCEDiag(E, diag::note_expr_divide_by_zero); LHS.divide(RHS, APFloat::rmNearestTiesToEven); break; } - if (LHS.isInfinity() || LHS.isNaN()) { + // [expr.pre]p4: + // If during the evaluation of an expression, the result is not + // mathematically defined [...], the behavior is undefined. + // FIXME: C++ rules require us to not conform to IEEE 754 here. + if (LHS.isNaN()) { Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN(); return Info.noteUndefinedBehavior(); } @@ -2428,6 +2555,21 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E, return true; } +/// Cast an lvalue referring to a derived class to a known base subobject. +static bool CastToBaseClass(EvalInfo &Info, const Expr *E, LValue &Result, + const CXXRecordDecl *DerivedRD, + const CXXRecordDecl *BaseRD) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!DerivedRD->isDerivedFrom(BaseRD, Paths)) + llvm_unreachable("Class must be derived from the passed in base class!"); + + for (CXXBasePathElement &Elem : Paths.front()) + if (!HandleLValueBase(Info, E, Result, Elem.Class, Elem.Base)) + return false; + return true; +} + /// Update LVal to refer to the given field, which must be a member of the type /// currently described by LVal. static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, @@ -2522,10 +2664,6 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, return true; } -static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, - QualType Type, const LValue &LVal, - APValue &RVal); - /// Try to evaluate the initializer for a variable declaration. /// /// \param Info Information about the ongoing evaluation. @@ -2643,6 +2781,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, /// Extract the value of a character from a string literal. static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, uint64_t Index) { + assert(!isa<SourceLocExpr>(Lit) && + "SourceLocExpr should have already been converted to a StringLiteral"); + // FIXME: Support MakeStringConstant if (const auto *ObjCEnc = dyn_cast<ObjCEncodeExpr>(Lit)) { std::string Str; @@ -2668,9 +2809,11 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, } // Expand a string literal into an array of characters. -static void expandStringLiteral(EvalInfo &Info, const Expr *Lit, +// +// FIXME: This is inefficient; we should probably introduce something similar +// to the LLVM ConstantDataArray to make this cheaper. +static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S, APValue &Result) { - const StringLiteral *S = cast<StringLiteral>(Lit); const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(S->getType()); assert(CAT && "string literal isn't an array"); @@ -2769,28 +2912,73 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E, return false; } +static bool lifetimeStartedInEvaluation(EvalInfo &Info, + APValue::LValueBase Base) { + // A temporary we created. + if (Base.getCallIndex()) + return true; + + auto *Evaluating = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); + if (!Evaluating) + return false; + + // The variable whose initializer we're evaluating. + if (auto *BaseD = Base.dyn_cast<const ValueDecl*>()) + if (declaresSameEntity(Evaluating, BaseD)) + return true; + + // A temporary lifetime-extended by the variable whose initializer we're + // evaluating. + if (auto *BaseE = Base.dyn_cast<const Expr *>()) + if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE)) + if (declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating)) + return true; + + return false; +} + namespace { /// A handle to a complete object (an object that is not a subobject of /// another object). struct CompleteObject { + /// The identity of the object. + APValue::LValueBase Base; /// The value of the complete object. APValue *Value; /// The type of the complete object. QualType Type; - bool LifetimeStartedInEvaluation; CompleteObject() : Value(nullptr) {} - CompleteObject(APValue *Value, QualType Type, - bool LifetimeStartedInEvaluation) - : Value(Value), Type(Type), - LifetimeStartedInEvaluation(LifetimeStartedInEvaluation) { - assert(Value && "missing value for complete object"); + CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type) + : Base(Base), Value(Value), Type(Type) {} + + bool mayReadMutableMembers(EvalInfo &Info) const { + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + // FIXME: Should we also allow this in C++11? + if (!Info.getLangOpts().CPlusPlus14) + return false; + return lifetimeStartedInEvaluation(Info, Base); } - explicit operator bool() const { return Value; } + explicit operator bool() const { return !Type.isNull(); } }; } // end anonymous namespace +static QualType getSubobjectType(QualType ObjType, QualType SubobjType, + bool IsMutable = false) { + // C++ [basic.type.qualifier]p1: + // - A const object is an object of type const T or a non-mutable subobject + // of a const object. + if (ObjType.isConstQualified() && !IsMutable) + SubobjType.addConst(); + // - A volatile object is an object of type const T or a subobject of a + // volatile object. + if (ObjType.isVolatileQualified()) + SubobjType.addVolatile(); + return SubobjType; +} + /// Find the designated sub-object of an rvalue. template<typename SubobjectHandler> typename SubobjectHandler::result_type @@ -2813,31 +3001,78 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, APValue *O = Obj.Value; QualType ObjType = Obj.Type; const FieldDecl *LastField = nullptr; - const bool MayReadMutableMembers = - Obj.LifetimeStartedInEvaluation && Info.getLangOpts().CPlusPlus14; + const FieldDecl *VolatileField = nullptr; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { - if (O->isUninit()) { + // Reading an indeterminate value is undefined, but assigning over one is OK. + if (O->isAbsent() || (O->isIndeterminate() && handler.AccessKind != AK_Assign)) { if (!Info.checkingPotentialConstantExpression()) - Info.FFDiag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + Info.FFDiag(E, diag::note_constexpr_access_uninit) + << handler.AccessKind << O->isIndeterminate(); return handler.failed(); } - if (I == N) { + // C++ [class.ctor]p5: + // const and volatile semantics are not applied on an object under + // construction. + if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) && + ObjType->isRecordType() && + Info.isEvaluatingConstructor( + Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(), + Sub.Entries.begin() + I)) != + ConstructionPhase::None) { + ObjType = Info.Ctx.getCanonicalType(ObjType); + ObjType.removeLocalConst(); + ObjType.removeLocalVolatile(); + } + + // If this is our last pass, check that the final object type is OK. + if (I == N || (I == N - 1 && ObjType->isAnyComplexType())) { + // Accesses to volatile objects are prohibited. + if (ObjType.isVolatileQualified() && isFormalAccess(handler.AccessKind)) { + if (Info.getLangOpts().CPlusPlus) { + int DiagKind; + SourceLocation Loc; + const NamedDecl *Decl = nullptr; + if (VolatileField) { + DiagKind = 2; + Loc = VolatileField->getLocation(); + Decl = VolatileField; + } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) { + DiagKind = 1; + Loc = VD->getLocation(); + Decl = VD; + } else { + DiagKind = 0; + if (auto *E = Obj.Base.dyn_cast<const Expr *>()) + Loc = E->getExprLoc(); + } + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) + << handler.AccessKind << DiagKind << Decl; + Info.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind; + } else { + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + } + return handler.failed(); + } + // If we are reading an object of class type, there may still be more // things we need to check: if there are any mutable subobjects, we // cannot perform this read. (This only happens when performing a trivial // copy or assignment.) if (ObjType->isRecordType() && handler.AccessKind == AK_Read && - !MayReadMutableMembers && diagnoseUnreadableFields(Info, E, ObjType)) + !Obj.mayReadMutableMembers(Info) && + diagnoseUnreadableFields(Info, E, ObjType)) return handler.failed(); + } + if (I == N) { if (!handler.found(*O, ObjType)) return false; // If we modified a bit-field, truncate it to the right width. - if (handler.AccessKind != AK_Read && + if (isModification(handler.AccessKind) && LastField && LastField->isBitField() && !truncateBitfieldValue(Info, E, *O, LastField)) return false; @@ -2850,7 +3085,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // Next subobject is an array element. const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); assert(CAT && "vla in literal type?"); - uint64_t Index = Sub.Entries[I].ArrayIndex; + uint64_t Index = Sub.Entries[I].getAsArrayIndex(); if (CAT->getSize().ule(Index)) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. @@ -2864,18 +3099,6 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, ObjType = CAT->getElementType(); - // An array object is represented as either an Array APValue or as an - // LValue which refers to a string literal. - if (O->isLValue()) { - assert(I == N - 1 && "extracting subobject of character?"); - assert(!O->hasLValuePath() || O->getLValuePath().empty()); - if (handler.AccessKind != AK_Read) - expandStringLiteral(Info, O->getLValueBase().get<const Expr *>(), - *O); - else - return handler.foundString(*O, ObjType, Index); - } - if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); else if (handler.AccessKind != AK_Read) { @@ -2885,7 +3108,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, O = &O->getArrayFiller(); } else if (ObjType->isAnyComplexType()) { // Next subobject is a complex number. - uint64_t Index = Sub.Entries[I].ArrayIndex; + uint64_t Index = Sub.Entries[I].getAsArrayIndex(); if (Index > 1) { if (Info.getLangOpts().CPlusPlus11) Info.FFDiag(E, diag::note_constexpr_access_past_end) @@ -2895,10 +3118,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, return handler.failed(); } - bool WasConstQualified = ObjType.isConstQualified(); - ObjType = ObjType->castAs<ComplexType>()->getElementType(); - if (WasConstQualified) - ObjType.addConst(); + ObjType = getSubobjectType( + ObjType, ObjType->castAs<ComplexType>()->getElementType()); assert(I == N - 1 && "extracting subobject of scalar?"); if (O->isComplexInt()) { @@ -2910,11 +3131,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, : O->getComplexFloatReal(), ObjType); } } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - // In C++14 onwards, it is permitted to read a mutable member whose - // lifetime began within the evaluation. - // FIXME: Should we also allow this in C++11? if (Field->isMutable() && handler.AccessKind == AK_Read && - !MayReadMutableMembers) { + !Obj.mayReadMutableMembers(Info)) { Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); @@ -2935,34 +3153,17 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } else O = &O->getStructField(Field->getFieldIndex()); - bool WasConstQualified = ObjType.isConstQualified(); - ObjType = Field->getType(); - if (WasConstQualified && !Field->isMutable()) - ObjType.addConst(); - - if (ObjType.isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - // FIXME: Include a description of the path to the volatile subobject. - Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) - << handler.AccessKind << 2 << Field; - Info.Note(Field->getLocation(), diag::note_declared_at); - } else { - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - } - return handler.failed(); - } - + ObjType = getSubobjectType(ObjType, Field->getType(), Field->isMutable()); LastField = Field; + if (Field->getType().isVolatileQualified()) + VolatileField = Field; } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); - bool WasConstQualified = ObjType.isConstQualified(); - ObjType = Info.Ctx.getRecordType(Base); - if (WasConstQualified) - ObjType.addConst(); + ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base)); } } } @@ -2988,11 +3189,6 @@ struct ExtractSubobjectHandler { Result = APValue(Value); return true; } - bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { - Result = APValue(extractStringLiteralCharacter( - Info, Subobj.getLValueBase().get<const Expr *>(), Character)); - return true; - } }; } // end anonymous namespace @@ -3050,9 +3246,6 @@ struct ModifySubobjectHandler { Value = NewVal.getFloat(); return true; } - bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { - llvm_unreachable("shouldn't encounter string elements with ExpandArrays"); - } }; } // end anonymous namespace @@ -3078,7 +3271,7 @@ static unsigned FindDesignatorMismatch(QualType ObjType, if (!ObjType.isNull() && (ObjType->isArrayType() || ObjType->isAnyComplexType())) { // Next subobject is an array element. - if (A.Entries[I].ArrayIndex != B.Entries[I].ArrayIndex) { + if (A.Entries[I].getAsArrayIndex() != B.Entries[I].getAsArrayIndex()) { WasArrayIndex = true; return I; } @@ -3087,7 +3280,8 @@ static unsigned FindDesignatorMismatch(QualType ObjType, else ObjType = ObjType->castAsArrayTypeUnsafe()->getElementType(); } else { - if (A.Entries[I].BaseOrMember != B.Entries[I].BaseOrMember) { + if (A.Entries[I].getAsBaseOrMember() != + B.Entries[I].getAsBaseOrMember()) { WasArrayIndex = false; return I; } @@ -3128,14 +3322,21 @@ static bool AreElementsOfSameArray(QualType ObjType, static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, const LValue &LVal, QualType LValType) { + if (LVal.InvalidBase) { + Info.FFDiag(E); + return CompleteObject(); + } + if (!LVal.Base) { Info.FFDiag(E, diag::note_constexpr_access_null) << AK; return CompleteObject(); } CallStackFrame *Frame = nullptr; + unsigned Depth = 0; if (LVal.getLValueCallIndex()) { - Frame = Info.getCallFrame(LVal.getLValueCallIndex()); + std::tie(Frame, Depth) = + Info.getCallFrameAndDepth(LVal.getLValueCallIndex()); if (!Frame) { Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1) << AK << LVal.Base.is<const ValueDecl*>(); @@ -3144,11 +3345,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } } + bool IsAccess = isFormalAccess(AK); + // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type // is not a constant expression (even if the object is non-volatile). We also // apply this rule to C++98, in order to conform to the expected 'volatile' // semantics. - if (LValType.isVolatileQualified()) { + if (IsAccess && LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) Info.FFDiag(E, diag::note_constexpr_access_volatile_type) << AK << LValType; @@ -3160,7 +3363,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // Compute value storage location and type of base object. APValue *BaseVal = nullptr; QualType BaseType = getType(LVal.Base); - bool LifetimeStartedInEvaluation = Frame; if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -3180,37 +3382,29 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, return CompleteObject(); } - // Accesses of volatile-qualified objects are not allowed. - if (BaseType.isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) - << AK << 1 << VD; - Info.Note(VD->getLocation(), diag::note_declared_at); - } else { - Info.FFDiag(E); - } - return CompleteObject(); - } - // Unless we're looking at a local variable or argument in a constexpr call, // the variable we're reading must be const. if (!Frame) { if (Info.getLangOpts().CPlusPlus14 && - VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) { + declaresSameEntity( + VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) { // OK, we can read and modify an object if we're in the process of // evaluating its initializer, because its lifetime began in this // evaluation. - } else if (AK != AK_Read) { - // All the remaining cases only permit reading. + } else if (isModification(AK)) { + // All the remaining cases do not permit modification of the object. Info.FFDiag(E, diag::note_constexpr_modify_global); return CompleteObject(); } else if (VD->isConstexpr()) { // OK, we can read this variable. } else if (BaseType->isIntegralOrEnumerationType()) { - // In OpenCL if a variable is in constant address space it is a const value. + // In OpenCL if a variable is in constant address space it is a const + // value. if (!(BaseType.isConstQualified() || (Info.getLangOpts().OpenCL && BaseType.getAddressSpace() == LangAS::opencl_constant))) { + if (!IsAccess) + return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); if (Info.getLangOpts().CPlusPlus) { Info.FFDiag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); @@ -3219,6 +3413,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } return CompleteObject(); } + } else if (!IsAccess) { + return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); } else if (BaseType->isFloatingType() && BaseType.isConstQualified()) { // We support folding of const floating-point types, in order to make // static const data members of such types (supported as an extension) @@ -3255,7 +3451,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!Frame) { if (const MaterializeTemporaryExpr *MTE = - dyn_cast<MaterializeTemporaryExpr>(Base)) { + dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) { assert(MTE->getStorageDuration() == SD_Static && "should have a frame for a non-global materialized temporary"); @@ -3278,6 +3474,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!(BaseType.isConstQualified() && BaseType->isIntegralOrEnumerationType()) && !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { + if (!IsAccess) + return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); return CompleteObject(); @@ -3285,38 +3483,22 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); assert(BaseVal && "got reference to unevaluated temporary"); - LifetimeStartedInEvaluation = true; } else { - Info.FFDiag(E); + if (!IsAccess) + return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); + APValue Val; + LVal.moveInto(Val); + Info.FFDiag(E, diag::note_constexpr_access_unreadable_object) + << AK + << Val.getAsString(Info.Ctx, + Info.Ctx.getLValueReferenceType(LValType)); + NoteLValueLocation(Info, LVal.Base); return CompleteObject(); } } else { BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } - - // Volatile temporary objects cannot be accessed in constant expressions. - if (BaseType.isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) - << AK << 0; - Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); - } else { - Info.FFDiag(E); - } - return CompleteObject(); - } - } - - // During the construction of an object, it is not yet 'const'. - // FIXME: This doesn't do quite the right thing for const subobjects of the - // object under construction. - if (Info.isEvaluatingConstructor(LVal.getLValueBase(), - LVal.getLValueCallIndex(), - LVal.getLValueVersion())) { - BaseType = Info.Ctx.getCanonicalType(BaseType); - BaseType.removeLocalConst(); - LifetimeStartedInEvaluation = true; } // In C++14, we can't safely access any mutable state when we might be @@ -3326,10 +3508,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // to be read here (but take care with 'mutable' fields). if ((Frame && Info.getLangOpts().CPlusPlus14 && Info.EvalStatus.HasSideEffects) || - (AK != AK_Read && Info.IsSpeculativelyEvaluating)) + (isModification(AK) && Depth < Info.SpeculativeEvaluationDepth)) return CompleteObject(); - return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation); + return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType); } /// Perform an lvalue-to-rvalue conversion on the given glvalue. This @@ -3351,6 +3533,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // Check for special cases where there is no existing APValue to look at. const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) { if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the @@ -3363,15 +3546,30 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, APValue Lit; if (!Evaluate(Lit, Info, CLE->getInitializer())) return false; - CompleteObject LitObj(&Lit, Base->getType(), false); + CompleteObject LitObj(LVal.Base, &Lit, Base->getType()); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { - // We represent a string literal array as an lvalue pointing at the - // corresponding expression, rather than building an array of chars. - // FIXME: Support ObjCEncodeExpr, MakeStringConstant - APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - CompleteObject StrObj(&Str, Base->getType(), false); - return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); + // Special-case character extraction so we don't have to construct an + // APValue for the whole string. + assert(LVal.Designator.Entries.size() <= 1 && + "Can only read characters from string literals"); + if (LVal.Designator.Entries.empty()) { + // Fail for now for LValue to RValue conversion of an array. + // (This shouldn't show up in C/C++, but it could be triggered by a + // weird EvaluateAsRValue call from a tool.) + Info.FFDiag(Conv); + return false; + } + if (LVal.Designator.isOnePastTheEnd()) { + if (Info.getLangOpts().CPlusPlus11) + Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK_Read; + else + Info.FFDiag(Conv); + return false; + } + uint64_t CharIndex = LVal.Designator.Entries[0].getAsArrayIndex(); + RVal = APValue(extractStringLiteralCharacter(Info, Base, CharIndex)); + return true; } } @@ -3497,9 +3695,6 @@ struct CompoundAssignSubobjectHandler { LVal.moveInto(Subobj); return true; } - bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { - llvm_unreachable("shouldn't encounter string elements here"); - } }; } // end anonymous namespace @@ -3648,9 +3843,6 @@ struct IncDecSubobjectHandler { LVal.moveInto(Subobj); return true; } - bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { - llvm_unreachable("shouldn't encounter string elements here"); - } }; } // end anonymous namespace @@ -4359,9 +4551,20 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; } + // DR1872: An instantiated virtual constexpr function can't be called in a + // constant expression (prior to C++20). We can still constant-fold such a + // call. + if (!Info.Ctx.getLangOpts().CPlusPlus2a && isa<CXXMethodDecl>(Declaration) && + cast<CXXMethodDecl>(Declaration)->isVirtual()) + Info.CCEDiag(CallLoc, diag::note_constexpr_virtual_call); + + if (Definition && Definition->isInvalidDecl()) { + Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr); + return false; + } + // Can we evaluate this function call? - if (Definition && Definition->isConstexpr() && - !Definition->isInvalidDecl() && Body) + if (Definition && Definition->isConstexpr() && Body) return true; if (Info.getLangOpts().CPlusPlus11) { @@ -4392,6 +4595,487 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; } +namespace { +struct CheckDynamicTypeHandler { + AccessKinds AccessKind; + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { return true; } + bool found(APSInt &Value, QualType SubobjType) { return true; } + bool found(APFloat &Value, QualType SubobjType) { return true; } +}; +} // end anonymous namespace + +/// Check that we can access the notional vptr of an object / determine its +/// dynamic type. +static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This, + AccessKinds AK, bool Polymorphic) { + if (This.Designator.Invalid) + return false; + + CompleteObject Obj = findCompleteObject(Info, E, AK, This, QualType()); + + if (!Obj) + return false; + + if (!Obj.Value) { + // The object is not usable in constant expressions, so we can't inspect + // its value to see if it's in-lifetime or what the active union members + // are. We can still check for a one-past-the-end lvalue. + if (This.Designator.isOnePastTheEnd() || + This.Designator.isMostDerivedAnUnsizedArray()) { + Info.FFDiag(E, This.Designator.isOnePastTheEnd() + ? diag::note_constexpr_access_past_end + : diag::note_constexpr_access_unsized_array) + << AK; + return false; + } else if (Polymorphic) { + // Conservatively refuse to perform a polymorphic operation if we would + // not be able to read a notional 'vptr' value. + APValue Val; + This.moveInto(Val); + QualType StarThisType = + Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx)); + Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type) + << AK << Val.getAsString(Info.Ctx, StarThisType); + return false; + } + return true; + } + + CheckDynamicTypeHandler Handler{AK}; + return Obj && findSubobject(Info, E, Obj, This.Designator, Handler); +} + +/// Check that the pointee of the 'this' pointer in a member function call is +/// either within its lifetime or in its period of construction or destruction. +static bool checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E, + const LValue &This) { + return checkDynamicType(Info, E, This, AK_MemberCall, false); +} + +struct DynamicType { + /// The dynamic class type of the object. + const CXXRecordDecl *Type; + /// The corresponding path length in the lvalue. + unsigned PathLength; +}; + +static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator, + unsigned PathLength) { + assert(PathLength >= Designator.MostDerivedPathLength && PathLength <= + Designator.Entries.size() && "invalid path length"); + return (PathLength == Designator.MostDerivedPathLength) + ? Designator.MostDerivedType->getAsCXXRecordDecl() + : getAsBaseClass(Designator.Entries[PathLength - 1]); +} + +/// Determine the dynamic type of an object. +static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E, + LValue &This, AccessKinds AK) { + // If we don't have an lvalue denoting an object of class type, there is no + // meaningful dynamic type. (We consider objects of non-class type to have no + // dynamic type.) + if (!checkDynamicType(Info, E, This, AK, true)) + return None; + + // Refuse to compute a dynamic type in the presence of virtual bases. This + // shouldn't happen other than in constant-folding situations, since literal + // types can't have virtual bases. + // + // Note that consumers of DynamicType assume that the type has no virtual + // bases, and will need modifications if this restriction is relaxed. + const CXXRecordDecl *Class = + This.Designator.MostDerivedType->getAsCXXRecordDecl(); + if (!Class || Class->getNumVBases()) { + Info.FFDiag(E); + return None; + } + + // FIXME: For very deep class hierarchies, it might be beneficial to use a + // binary search here instead. But the overwhelmingly common case is that + // we're not in the middle of a constructor, so it probably doesn't matter + // in practice. + ArrayRef<APValue::LValuePathEntry> Path = This.Designator.Entries; + for (unsigned PathLength = This.Designator.MostDerivedPathLength; + PathLength <= Path.size(); ++PathLength) { + switch (Info.isEvaluatingConstructor(This.getLValueBase(), + Path.slice(0, PathLength))) { + case ConstructionPhase::Bases: + // We're constructing a base class. This is not the dynamic type. + break; + + case ConstructionPhase::None: + case ConstructionPhase::AfterBases: + // We've finished constructing the base classes, so this is the dynamic + // type. + return DynamicType{getBaseClassType(This.Designator, PathLength), + PathLength}; + } + } + + // CWG issue 1517: we're constructing a base class of the object described by + // 'This', so that object has not yet begun its period of construction and + // any polymorphic operation on it results in undefined behavior. + Info.FFDiag(E); + return None; +} + +/// Perform virtual dispatch. +static const CXXMethodDecl *HandleVirtualDispatch( + EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found, + llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) { + Optional<DynamicType> DynType = + ComputeDynamicType(Info, E, This, AK_MemberCall); + if (!DynType) + return nullptr; + + // Find the final overrider. It must be declared in one of the classes on the + // path from the dynamic type to the static type. + // FIXME: If we ever allow literal types to have virtual base classes, that + // won't be true. + const CXXMethodDecl *Callee = Found; + unsigned PathLength = DynType->PathLength; + for (/**/; PathLength <= This.Designator.Entries.size(); ++PathLength) { + const CXXRecordDecl *Class = getBaseClassType(This.Designator, PathLength); + const CXXMethodDecl *Overrider = + Found->getCorrespondingMethodDeclaredInClass(Class, false); + if (Overrider) { + Callee = Overrider; + break; + } + } + + // C++2a [class.abstract]p6: + // the effect of making a virtual call to a pure virtual function [...] is + // undefined + if (Callee->isPure()) { + Info.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << Callee; + Info.Note(Callee->getLocation(), diag::note_declared_at); + return nullptr; + } + + // If necessary, walk the rest of the path to determine the sequence of + // covariant adjustment steps to apply. + if (!Info.Ctx.hasSameUnqualifiedType(Callee->getReturnType(), + Found->getReturnType())) { + CovariantAdjustmentPath.push_back(Callee->getReturnType()); + for (unsigned CovariantPathLength = PathLength + 1; + CovariantPathLength != This.Designator.Entries.size(); + ++CovariantPathLength) { + const CXXRecordDecl *NextClass = + getBaseClassType(This.Designator, CovariantPathLength); + const CXXMethodDecl *Next = + Found->getCorrespondingMethodDeclaredInClass(NextClass, false); + if (Next && !Info.Ctx.hasSameUnqualifiedType( + Next->getReturnType(), CovariantAdjustmentPath.back())) + CovariantAdjustmentPath.push_back(Next->getReturnType()); + } + if (!Info.Ctx.hasSameUnqualifiedType(Found->getReturnType(), + CovariantAdjustmentPath.back())) + CovariantAdjustmentPath.push_back(Found->getReturnType()); + } + + // Perform 'this' adjustment. + if (!CastToDerivedClass(Info, E, This, Callee->getParent(), PathLength)) + return nullptr; + + return Callee; +} + +/// Perform the adjustment from a value returned by a virtual function to +/// a value of the statically expected type, which may be a pointer or +/// reference to a base class of the returned type. +static bool HandleCovariantReturnAdjustment(EvalInfo &Info, const Expr *E, + APValue &Result, + ArrayRef<QualType> Path) { + assert(Result.isLValue() && + "unexpected kind of APValue for covariant return"); + if (Result.isNullPointer()) + return true; + + LValue LVal; + LVal.setFrom(Info.Ctx, Result); + + const CXXRecordDecl *OldClass = Path[0]->getPointeeCXXRecordDecl(); + for (unsigned I = 1; I != Path.size(); ++I) { + const CXXRecordDecl *NewClass = Path[I]->getPointeeCXXRecordDecl(); + assert(OldClass && NewClass && "unexpected kind of covariant return"); + if (OldClass != NewClass && + !CastToBaseClass(Info, E, LVal, OldClass, NewClass)) + return false; + OldClass = NewClass; + } + + LVal.moveInto(Result); + return true; +} + +/// Determine whether \p Base, which is known to be a direct base class of +/// \p Derived, is a public base class. +static bool isBaseClassPublic(const CXXRecordDecl *Derived, + const CXXRecordDecl *Base) { + for (const CXXBaseSpecifier &BaseSpec : Derived->bases()) { + auto *BaseClass = BaseSpec.getType()->getAsCXXRecordDecl(); + if (BaseClass && declaresSameEntity(BaseClass, Base)) + return BaseSpec.getAccessSpecifier() == AS_public; + } + llvm_unreachable("Base is not a direct base of Derived"); +} + +/// Apply the given dynamic cast operation on the provided lvalue. +/// +/// This implements the hard case of dynamic_cast, requiring a "runtime check" +/// to find a suitable target subobject. +static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, + LValue &Ptr) { + // We can't do anything with a non-symbolic pointer value. + SubobjectDesignator &D = Ptr.Designator; + if (D.Invalid) + return false; + + // C++ [expr.dynamic.cast]p6: + // If v is a null pointer value, the result is a null pointer value. + if (Ptr.isNullPointer() && !E->isGLValue()) + return true; + + // For all the other cases, we need the pointer to point to an object within + // its lifetime / period of construction / destruction, and we need to know + // its dynamic type. + Optional<DynamicType> DynType = + ComputeDynamicType(Info, E, Ptr, AK_DynamicCast); + if (!DynType) + return false; + + // C++ [expr.dynamic.cast]p7: + // If T is "pointer to cv void", then the result is a pointer to the most + // derived object + if (E->getType()->isVoidPointerType()) + return CastToDerivedClass(Info, E, Ptr, DynType->Type, DynType->PathLength); + + const CXXRecordDecl *C = E->getTypeAsWritten()->getPointeeCXXRecordDecl(); + assert(C && "dynamic_cast target is not void pointer nor class"); + CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C)); + + auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) { + // C++ [expr.dynamic.cast]p9: + if (!E->isGLValue()) { + // The value of a failed cast to pointer type is the null pointer value + // of the required result type. + auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType()); + Ptr.setNull(E->getType(), TargetVal); + return true; + } + + // A failed cast to reference type throws [...] std::bad_cast. + unsigned DiagKind; + if (!Paths && (declaresSameEntity(DynType->Type, C) || + DynType->Type->isDerivedFrom(C))) + DiagKind = 0; + else if (!Paths || Paths->begin() == Paths->end()) + DiagKind = 1; + else if (Paths->isAmbiguous(CQT)) + DiagKind = 2; + else { + assert(Paths->front().Access != AS_public && "why did the cast fail?"); + DiagKind = 3; + } + Info.FFDiag(E, diag::note_constexpr_dynamic_cast_to_reference_failed) + << DiagKind << Ptr.Designator.getType(Info.Ctx) + << Info.Ctx.getRecordType(DynType->Type) + << E->getType().getUnqualifiedType(); + return false; + }; + + // Runtime check, phase 1: + // Walk from the base subobject towards the derived object looking for the + // target type. + for (int PathLength = Ptr.Designator.Entries.size(); + PathLength >= (int)DynType->PathLength; --PathLength) { + const CXXRecordDecl *Class = getBaseClassType(Ptr.Designator, PathLength); + if (declaresSameEntity(Class, C)) + return CastToDerivedClass(Info, E, Ptr, Class, PathLength); + // We can only walk across public inheritance edges. + if (PathLength > (int)DynType->PathLength && + !isBaseClassPublic(getBaseClassType(Ptr.Designator, PathLength - 1), + Class)) + return RuntimeCheckFailed(nullptr); + } + + // Runtime check, phase 2: + // Search the dynamic type for an unambiguous public base of type C. + CXXBasePaths Paths(/*FindAmbiguities=*/true, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (DynType->Type->isDerivedFrom(C, Paths) && !Paths.isAmbiguous(CQT) && + Paths.front().Access == AS_public) { + // Downcast to the dynamic type... + if (!CastToDerivedClass(Info, E, Ptr, DynType->Type, DynType->PathLength)) + return false; + // ... then upcast to the chosen base class subobject. + for (CXXBasePathElement &Elem : Paths.front()) + if (!HandleLValueBase(Info, E, Ptr, Elem.Class, Elem.Base)) + return false; + return true; + } + + // Otherwise, the runtime check fails. + return RuntimeCheckFailed(&Paths); +} + +namespace { +struct StartLifetimeOfUnionMemberHandler { + const FieldDecl *Field; + + static const AccessKinds AccessKind = AK_Assign; + + APValue getDefaultInitValue(QualType SubobjType) { + if (auto *RD = SubobjType->getAsCXXRecordDecl()) { + if (RD->isUnion()) + return APValue((const FieldDecl*)nullptr); + + APValue Struct(APValue::UninitStruct(), RD->getNumBases(), + std::distance(RD->field_begin(), RD->field_end())); + + unsigned Index = 0; + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + End = RD->bases_end(); I != End; ++I, ++Index) + Struct.getStructBase(Index) = getDefaultInitValue(I->getType()); + + for (const auto *I : RD->fields()) { + if (I->isUnnamedBitfield()) + continue; + Struct.getStructField(I->getFieldIndex()) = + getDefaultInitValue(I->getType()); + } + return Struct; + } + + if (auto *AT = dyn_cast_or_null<ConstantArrayType>( + SubobjType->getAsArrayTypeUnsafe())) { + APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue()); + if (Array.hasArrayFiller()) + Array.getArrayFiller() = getDefaultInitValue(AT->getElementType()); + return Array; + } + + return APValue::IndeterminateValue(); + } + + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + // We are supposed to perform no initialization but begin the lifetime of + // the object. We interpret that as meaning to do what default + // initialization of the object would do if all constructors involved were + // trivial: + // * All base, non-variant member, and array element subobjects' lifetimes + // begin + // * No variant members' lifetimes begin + // * All scalar subobjects whose lifetimes begin have indeterminate values + assert(SubobjType->isUnionType()); + if (!declaresSameEntity(Subobj.getUnionField(), Field)) + Subobj.setUnion(Field, getDefaultInitValue(Field->getType())); + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + llvm_unreachable("wrong value kind for union object"); + } + bool found(APFloat &Value, QualType SubobjType) { + llvm_unreachable("wrong value kind for union object"); + } +}; +} // end anonymous namespace + +const AccessKinds StartLifetimeOfUnionMemberHandler::AccessKind; + +/// Handle a builtin simple-assignment or a call to a trivial assignment +/// operator whose left-hand side might involve a union member access. If it +/// does, implicitly start the lifetime of any accessed union elements per +/// C++20 [class.union]5. +static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr, + const LValue &LHS) { + if (LHS.InvalidBase || LHS.Designator.Invalid) + return false; + + llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths; + // C++ [class.union]p5: + // define the set S(E) of subexpressions of E as follows: + unsigned PathLength = LHS.Designator.Entries.size(); + for (const Expr *E = LHSExpr; E != nullptr;) { + // -- If E is of the form A.B, S(E) contains the elements of S(A)... + if (auto *ME = dyn_cast<MemberExpr>(E)) { + auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); + if (!FD) + break; + + // ... and also contains A.B if B names a union member + if (FD->getParent()->isUnion()) + UnionPathLengths.push_back({PathLength - 1, FD}); + + E = ME->getBase(); + --PathLength; + assert(declaresSameEntity(FD, + LHS.Designator.Entries[PathLength] + .getAsBaseOrMember().getPointer())); + + // -- If E is of the form A[B] and is interpreted as a built-in array + // subscripting operator, S(E) is [S(the array operand, if any)]. + } else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) { + // Step over an ArrayToPointerDecay implicit cast. + auto *Base = ASE->getBase()->IgnoreImplicit(); + if (!Base->getType()->isArrayType()) + break; + + E = Base; + --PathLength; + + } else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) { + // Step over a derived-to-base conversion. + E = ICE->getSubExpr(); + if (ICE->getCastKind() == CK_NoOp) + continue; + if (ICE->getCastKind() != CK_DerivedToBase && + ICE->getCastKind() != CK_UncheckedDerivedToBase) + break; + // Walk path backwards as we walk up from the base to the derived class. + for (const CXXBaseSpecifier *Elt : llvm::reverse(ICE->path())) { + --PathLength; + (void)Elt; + assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(), + LHS.Designator.Entries[PathLength] + .getAsBaseOrMember().getPointer())); + } + + // -- Otherwise, S(E) is empty. + } else { + break; + } + } + + // Common case: no unions' lifetimes are started. + if (UnionPathLengths.empty()) + return true; + + // if modification of X [would access an inactive union member], an object + // of the type of X is implicitly created + CompleteObject Obj = + findCompleteObject(Info, LHSExpr, AK_Assign, LHS, LHSExpr->getType()); + if (!Obj) + return false; + for (std::pair<unsigned, const FieldDecl *> LengthAndField : + llvm::reverse(UnionPathLengths)) { + // Form a designator for the union object. + SubobjectDesignator D = LHS.Designator; + D.truncate(Info.Ctx, LHS.Base, LengthAndField.first); + + StartLifetimeOfUnionMemberHandler StartLifetime{LengthAndField.second}; + if (!findSubobject(Info, LHSExpr, Obj, D, StartLifetime)) + return false; + } + + return true; +} + /// Determine if a class has any fields that might need to be copied by a /// trivial copy or move operation. static bool hasFields(const CXXRecordDecl *RD) { @@ -4413,9 +5097,25 @@ typedef SmallVector<APValue, 8> ArgVector; } /// EvaluateArgs - Evaluate the arguments to a function call. -static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, - EvalInfo &Info) { +static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues, + EvalInfo &Info, const FunctionDecl *Callee) { bool Success = true; + llvm::SmallBitVector ForbiddenNullArgs; + if (Callee->hasAttr<NonNullAttr>()) { + ForbiddenNullArgs.resize(Args.size()); + for (const auto *Attr : Callee->specific_attrs<NonNullAttr>()) { + if (!Attr->args_size()) { + ForbiddenNullArgs.set(); + break; + } else + for (auto Idx : Attr->args()) { + unsigned ASTIdx = Idx.getASTIndex(); + if (ASTIdx >= Args.size()) + continue; + ForbiddenNullArgs[ASTIdx] = 1; + } + } + } for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) { @@ -4424,6 +5124,13 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, if (!Info.noteFailure()) return false; Success = false; + } else if (!ForbiddenNullArgs.empty() && + ForbiddenNullArgs[I - Args.begin()] && + ArgValues[I - Args.begin()].isNullPointer()) { + Info.CCEDiag(*I, diag::note_non_null_attribute_failed); + if (!Info.noteFailure()) + return false; + Success = false; } } return Success; @@ -4436,7 +5143,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc, EvalInfo &Info, APValue &Result, const LValue *ResultSlot) { ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) + if (!EvaluateArgs(Args, ArgValues, Info, Callee)) return false; if (!Info.CheckCallLimit(CallLoc)) @@ -4462,6 +5169,9 @@ static bool HandleFunctionCall(SourceLocation CallLoc, if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS, RHSValue)) return false; + if (Info.getLangOpts().CPlusPlus2a && MD->isTrivial() && + !HandleUnionActiveMemberChange(Info, Args[0], *This)) + return false; if (!handleAssignment(Info, Args[0], *This, MD->getThisType(), RHSValue)) return false; @@ -4505,8 +5215,9 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, {This.getLValueBase(), - {This.getLValueCallIndex(), This.getLValueVersion()}}); + Info, + ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries}, + RD->getNumBases()); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4544,7 +5255,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } // Reserve space for the struct members. - if (!RD->isUnion() && Result.isUninit()) + if (!RD->isUnion() && !Result.hasValue()) Result = APValue(APValue::UninitStruct(), RD->getNumBases(), std::distance(RD->field_begin(), RD->field_end())); @@ -4601,7 +5312,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // subobject other than the first. // FIXME: In this case, the values of the other subobjects are // specified, since zero-initialization sets all padding bits to zero. - if (Value->isUninit() || + if (!Value->hasValue() || (Value->isUnion() && Value->getUnionField() != FD)) { if (CD->isUnion()) *Value = APValue(FD); @@ -4640,6 +5351,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, return false; Success = false; } + + // This is the point at which the dynamic type of the object becomes this + // class type. + if (I->isBaseInitializer() && BasesSeen == RD->getNumBases()) + EvalObj.finishedConstructingBases(); } return Success && @@ -4651,7 +5367,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, const CXXConstructorDecl *Definition, EvalInfo &Info, APValue &Result) { ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) + if (!EvaluateArgs(Args, ArgValues, Info, Definition)) return false; return HandleConstructorCall(E, This, ArgValues.data(), Definition, @@ -4663,6 +5379,491 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, //===----------------------------------------------------------------------===// namespace { +class BitCastBuffer { + // FIXME: We're going to need bit-level granularity when we support + // bit-fields. + // FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but + // we don't support a host or target where that is the case. Still, we should + // use a more generic type in case we ever do. + SmallVector<Optional<unsigned char>, 32> Bytes; + + static_assert(std::numeric_limits<unsigned char>::digits >= 8, + "Need at least 8 bit unsigned char"); + + bool TargetIsLittleEndian; + +public: + BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian) + : Bytes(Width.getQuantity()), + TargetIsLittleEndian(TargetIsLittleEndian) {} + + LLVM_NODISCARD + bool readObject(CharUnits Offset, CharUnits Width, + SmallVectorImpl<unsigned char> &Output) const { + for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) { + // If a byte of an integer is uninitialized, then the whole integer is + // uninitalized. + if (!Bytes[I.getQuantity()]) + return false; + Output.push_back(*Bytes[I.getQuantity()]); + } + if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian) + std::reverse(Output.begin(), Output.end()); + return true; + } + + void writeObject(CharUnits Offset, SmallVectorImpl<unsigned char> &Input) { + if (llvm::sys::IsLittleEndianHost != TargetIsLittleEndian) + std::reverse(Input.begin(), Input.end()); + + size_t Index = 0; + for (unsigned char Byte : Input) { + assert(!Bytes[Offset.getQuantity() + Index] && "overwriting a byte?"); + Bytes[Offset.getQuantity() + Index] = Byte; + ++Index; + } + } + + size_t size() { return Bytes.size(); } +}; + +/// Traverse an APValue to produce an BitCastBuffer, emulating how the current +/// target would represent the value at runtime. +class APValueToBufferConverter { + EvalInfo &Info; + BitCastBuffer Buffer; + const CastExpr *BCE; + + APValueToBufferConverter(EvalInfo &Info, CharUnits ObjectWidth, + const CastExpr *BCE) + : Info(Info), + Buffer(ObjectWidth, Info.Ctx.getTargetInfo().isLittleEndian()), + BCE(BCE) {} + + bool visit(const APValue &Val, QualType Ty) { + return visit(Val, Ty, CharUnits::fromQuantity(0)); + } + + // Write out Val with type Ty into Buffer starting at Offset. + bool visit(const APValue &Val, QualType Ty, CharUnits Offset) { + assert((size_t)Offset.getQuantity() <= Buffer.size()); + + // As a special case, nullptr_t has an indeterminate value. + if (Ty->isNullPtrType()) + return true; + + // Dig through Src to find the byte at SrcOffset. + switch (Val.getKind()) { + case APValue::Indeterminate: + case APValue::None: + return true; + + case APValue::Int: + return visitInt(Val.getInt(), Ty, Offset); + case APValue::Float: + return visitFloat(Val.getFloat(), Ty, Offset); + case APValue::Array: + return visitArray(Val, Ty, Offset); + case APValue::Struct: + return visitRecord(Val, Ty, Offset); + + case APValue::ComplexInt: + case APValue::ComplexFloat: + case APValue::Vector: + case APValue::FixedPoint: + // FIXME: We should support these. + + case APValue::Union: + case APValue::MemberPointer: + case APValue::AddrLabelDiff: { + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_type) + << Ty; + return false; + } + + case APValue::LValue: + llvm_unreachable("LValue subobject in bit_cast?"); + } + llvm_unreachable("Unhandled APValue::ValueKind"); + } + + bool visitRecord(const APValue &Val, QualType Ty, CharUnits Offset) { + const RecordDecl *RD = Ty->getAsRecordDecl(); + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); + + // Visit the base classes. + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) { + const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I]; + CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); + + if (!visitRecord(Val.getStructBase(I), BS.getType(), + Layout.getBaseClassOffset(BaseDecl) + Offset)) + return false; + } + } + + // Visit the fields. + unsigned FieldIdx = 0; + for (FieldDecl *FD : RD->fields()) { + if (FD->isBitField()) { + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_bitfield); + return false; + } + + uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx); + + assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0 && + "only bit-fields can have sub-char alignment"); + CharUnits FieldOffset = + Info.Ctx.toCharUnitsFromBits(FieldOffsetBits) + Offset; + QualType FieldTy = FD->getType(); + if (!visit(Val.getStructField(FieldIdx), FieldTy, FieldOffset)) + return false; + ++FieldIdx; + } + + return true; + } + + bool visitArray(const APValue &Val, QualType Ty, CharUnits Offset) { + const auto *CAT = + dyn_cast_or_null<ConstantArrayType>(Ty->getAsArrayTypeUnsafe()); + if (!CAT) + return false; + + CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(CAT->getElementType()); + unsigned NumInitializedElts = Val.getArrayInitializedElts(); + unsigned ArraySize = Val.getArraySize(); + // First, initialize the initialized elements. + for (unsigned I = 0; I != NumInitializedElts; ++I) { + const APValue &SubObj = Val.getArrayInitializedElt(I); + if (!visit(SubObj, CAT->getElementType(), Offset + I * ElemWidth)) + return false; + } + + // Next, initialize the rest of the array using the filler. + if (Val.hasArrayFiller()) { + const APValue &Filler = Val.getArrayFiller(); + for (unsigned I = NumInitializedElts; I != ArraySize; ++I) { + if (!visit(Filler, CAT->getElementType(), Offset + I * ElemWidth)) + return false; + } + } + + return true; + } + + bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) { + CharUnits Width = Info.Ctx.getTypeSizeInChars(Ty); + SmallVector<unsigned char, 8> Bytes(Width.getQuantity()); + llvm::StoreIntToMemory(Val, &*Bytes.begin(), Width.getQuantity()); + Buffer.writeObject(Offset, Bytes); + return true; + } + + bool visitFloat(const APFloat &Val, QualType Ty, CharUnits Offset) { + APSInt AsInt(Val.bitcastToAPInt()); + return visitInt(AsInt, Ty, Offset); + } + +public: + static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src, + const CastExpr *BCE) { + CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType()); + APValueToBufferConverter Converter(Info, DstSize, BCE); + if (!Converter.visit(Src, BCE->getSubExpr()->getType())) + return None; + return Converter.Buffer; + } +}; + +/// Write an BitCastBuffer into an APValue. +class BufferToAPValueConverter { + EvalInfo &Info; + const BitCastBuffer &Buffer; + const CastExpr *BCE; + + BufferToAPValueConverter(EvalInfo &Info, const BitCastBuffer &Buffer, + const CastExpr *BCE) + : Info(Info), Buffer(Buffer), BCE(BCE) {} + + // Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast + // with an invalid type, so anything left is a deficiency on our part (FIXME). + // Ideally this will be unreachable. + llvm::NoneType unsupportedType(QualType Ty) { + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_type) + << Ty; + return None; + } + + Optional<APValue> visit(const BuiltinType *T, CharUnits Offset, + const EnumType *EnumSugar = nullptr) { + if (T->isNullPtrType()) { + uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0)); + return APValue((Expr *)nullptr, + /*Offset=*/CharUnits::fromQuantity(NullValue), + APValue::NoLValuePath{}, /*IsNullPtr=*/true); + } + + CharUnits SizeOf = Info.Ctx.getTypeSizeInChars(T); + SmallVector<uint8_t, 8> Bytes; + if (!Buffer.readObject(Offset, SizeOf, Bytes)) { + // If this is std::byte or unsigned char, then its okay to store an + // indeterminate value. + bool IsStdByte = EnumSugar && EnumSugar->isStdByteType(); + bool IsUChar = + !EnumSugar && (T->isSpecificBuiltinType(BuiltinType::UChar) || + T->isSpecificBuiltinType(BuiltinType::Char_U)); + if (!IsStdByte && !IsUChar) { + QualType DisplayType(EnumSugar ? (const Type *)EnumSugar : T, 0); + Info.FFDiag(BCE->getExprLoc(), + diag::note_constexpr_bit_cast_indet_dest) + << DisplayType << Info.Ctx.getLangOpts().CharIsSigned; + return None; + } + + return APValue::IndeterminateValue(); + } + + APSInt Val(SizeOf.getQuantity() * Info.Ctx.getCharWidth(), true); + llvm::LoadIntFromMemory(Val, &*Bytes.begin(), Bytes.size()); + + if (T->isIntegralOrEnumerationType()) { + Val.setIsSigned(T->isSignedIntegerOrEnumerationType()); + return APValue(Val); + } + + if (T->isRealFloatingType()) { + const llvm::fltSemantics &Semantics = + Info.Ctx.getFloatTypeSemantics(QualType(T, 0)); + return APValue(APFloat(Semantics, Val)); + } + + return unsupportedType(QualType(T, 0)); + } + + Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) { + const RecordDecl *RD = RTy->getAsRecordDecl(); + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); + + unsigned NumBases = 0; + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + NumBases = CXXRD->getNumBases(); + + APValue ResultVal(APValue::UninitStruct(), NumBases, + std::distance(RD->field_begin(), RD->field_end())); + + // Visit the base classes. + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (size_t I = 0, E = CXXRD->getNumBases(); I != E; ++I) { + const CXXBaseSpecifier &BS = CXXRD->bases_begin()[I]; + CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); + if (BaseDecl->isEmpty() || + Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) + continue; + + Optional<APValue> SubObj = visitType( + BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset); + if (!SubObj) + return None; + ResultVal.getStructBase(I) = *SubObj; + } + } + + // Visit the fields. + unsigned FieldIdx = 0; + for (FieldDecl *FD : RD->fields()) { + // FIXME: We don't currently support bit-fields. A lot of the logic for + // this is in CodeGen, so we need to factor it around. + if (FD->isBitField()) { + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_bitfield); + return None; + } + + uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx); + assert(FieldOffsetBits % Info.Ctx.getCharWidth() == 0); + + CharUnits FieldOffset = + CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) + + Offset; + QualType FieldTy = FD->getType(); + Optional<APValue> SubObj = visitType(FieldTy, FieldOffset); + if (!SubObj) + return None; + ResultVal.getStructField(FieldIdx) = *SubObj; + ++FieldIdx; + } + + return ResultVal; + } + + Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) { + QualType RepresentationType = Ty->getDecl()->getIntegerType(); + assert(!RepresentationType.isNull() && + "enum forward decl should be caught by Sema"); + const BuiltinType *AsBuiltin = + RepresentationType.getCanonicalType()->getAs<BuiltinType>(); + assert(AsBuiltin && "non-integral enum underlying type?"); + // Recurse into the underlying type. Treat std::byte transparently as + // unsigned char. + return visit(AsBuiltin, Offset, /*EnumTy=*/Ty); + } + + Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) { + size_t Size = Ty->getSize().getLimitedValue(); + CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType()); + + APValue ArrayValue(APValue::UninitArray(), Size, Size); + for (size_t I = 0; I != Size; ++I) { + Optional<APValue> ElementValue = + visitType(Ty->getElementType(), Offset + I * ElementWidth); + if (!ElementValue) + return None; + ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue); + } + + return ArrayValue; + } + + Optional<APValue> visit(const Type *Ty, CharUnits Offset) { + return unsupportedType(QualType(Ty, 0)); + } + + Optional<APValue> visitType(QualType Ty, CharUnits Offset) { + QualType Can = Ty.getCanonicalType(); + + switch (Can->getTypeClass()) { +#define TYPE(Class, Base) \ + case Type::Class: \ + return visit(cast<Class##Type>(Can.getTypePtr()), Offset); +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) \ + case Type::Class: \ + llvm_unreachable("non-canonical type should be impossible!"); +#define DEPENDENT_TYPE(Class, Base) \ + case Type::Class: \ + llvm_unreachable( \ + "dependent types aren't supported in the constant evaluator!"); +#define NON_CANONICAL_UNLESS_DEPENDENT(Class, Base) \ + case Type::Class: \ + llvm_unreachable("either dependent or not canonical!"); +#include "clang/AST/TypeNodes.def" + } + llvm_unreachable("Unhandled Type::TypeClass"); + } + +public: + // Pull out a full value of type DstType. + static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer, + const CastExpr *BCE) { + BufferToAPValueConverter Converter(Info, Buffer, BCE); + return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0)); + } +}; + +static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, + QualType Ty, EvalInfo *Info, + const ASTContext &Ctx, + bool CheckingDest) { + Ty = Ty.getCanonicalType(); + + auto diag = [&](int Reason) { + if (Info) + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_type) + << CheckingDest << (Reason == 4) << Reason; + return false; + }; + auto note = [&](int Construct, QualType NoteTy, SourceLocation NoteLoc) { + if (Info) + Info->Note(NoteLoc, diag::note_constexpr_bit_cast_invalid_subtype) + << NoteTy << Construct << Ty; + return false; + }; + + if (Ty->isUnionType()) + return diag(0); + if (Ty->isPointerType()) + return diag(1); + if (Ty->isMemberPointerType()) + return diag(2); + if (Ty.isVolatileQualified()) + return diag(3); + + if (RecordDecl *Record = Ty->getAsRecordDecl()) { + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(Record)) { + for (CXXBaseSpecifier &BS : CXXRD->bases()) + if (!checkBitCastConstexprEligibilityType(Loc, BS.getType(), Info, Ctx, + CheckingDest)) + return note(1, BS.getType(), BS.getBeginLoc()); + } + for (FieldDecl *FD : Record->fields()) { + if (FD->getType()->isReferenceType()) + return diag(4); + if (!checkBitCastConstexprEligibilityType(Loc, FD->getType(), Info, Ctx, + CheckingDest)) + return note(0, FD->getType(), FD->getBeginLoc()); + } + } + + if (Ty->isArrayType() && + !checkBitCastConstexprEligibilityType(Loc, Ctx.getBaseElementType(Ty), + Info, Ctx, CheckingDest)) + return false; + + return true; +} + +static bool checkBitCastConstexprEligibility(EvalInfo *Info, + const ASTContext &Ctx, + const CastExpr *BCE) { + bool DestOK = checkBitCastConstexprEligibilityType( + BCE->getBeginLoc(), BCE->getType(), Info, Ctx, true); + bool SourceOK = DestOK && checkBitCastConstexprEligibilityType( + BCE->getBeginLoc(), + BCE->getSubExpr()->getType(), Info, Ctx, false); + return SourceOK; +} + +static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, + APValue &SourceValue, + const CastExpr *BCE) { + assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && + "no host or target supports non 8-bit chars"); + assert(SourceValue.isLValue() && + "LValueToRValueBitcast requires an lvalue operand!"); + + if (!checkBitCastConstexprEligibility(&Info, Info.Ctx, BCE)) + return false; + + LValue SourceLValue; + APValue SourceRValue; + SourceLValue.setFrom(Info.Ctx, SourceValue); + if (!handleLValueToRValueConversion(Info, BCE, + BCE->getSubExpr()->getType().withConst(), + SourceLValue, SourceRValue)) + return false; + + // Read out SourceValue into a char buffer. + Optional<BitCastBuffer> Buffer = + APValueToBufferConverter::convert(Info, SourceRValue, BCE); + if (!Buffer) + return false; + + // Write out the buffer into a new APValue. + Optional<APValue> MaybeDestValue = + BufferToAPValueConverter::convert(Info, *Buffer, BCE); + if (!MaybeDestValue) + return false; + + DestValue = std::move(*MaybeDestValue); + return true; +} + template <class Derived> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> { @@ -4771,6 +5972,7 @@ public: { return StmtVisitorTy::Visit(E->getReplacement()); } bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { TempVersionRAII RAII(*Info.CurrentCall); + SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope); return StmtVisitorTy::Visit(E->getExpr()); } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { @@ -4778,8 +5980,10 @@ public: // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) return Error(E); + SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope); return StmtVisitorTy::Visit(E->getExpr()); } + // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. bool VisitExprWithCleanups(const ExprWithCleanups *E) @@ -4790,7 +5994,11 @@ public: return static_cast<Derived*>(this)->VisitCastExpr(E); } bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; + if (!Info.Ctx.getLangOpts().CPlusPlus2a) + CCEDiag(E, diag::note_constexpr_invalid_cast) << 1; + return static_cast<Derived*>(this)->VisitCastExpr(E); + } + bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) { return static_cast<Derived*>(this)->VisitCastExpr(E); } @@ -4884,25 +6092,26 @@ public: // Extract function decl and 'this' pointer from the callee. if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) { - const ValueDecl *Member = nullptr; + const CXXMethodDecl *Member = nullptr; if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) { // Explicit bound member calls, such as x.f() or p->g(); if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal)) return false; - Member = ME->getMemberDecl(); + Member = dyn_cast<CXXMethodDecl>(ME->getMemberDecl()); + if (!Member) + return Error(Callee); This = &ThisVal; HasQualifier = ME->hasQualifier(); } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) { // Indirect bound member calls ('.*' or '->*'). - Member = HandleMemberPointerAccess(Info, BE, ThisVal, false); - if (!Member) return false; + Member = dyn_cast_or_null<CXXMethodDecl>( + HandleMemberPointerAccess(Info, BE, ThisVal, false)); + if (!Member) + return Error(Callee); This = &ThisVal; } else return Error(Callee); - - FD = dyn_cast<FunctionDecl>(Member); - if (!FD) - return Error(Callee); + FD = Member; } else if (CalleeType->isFunctionPointerType()) { LValue Call; if (!EvaluatePointer(Callee, Call, Info)) @@ -4969,19 +6178,24 @@ public: } else FD = LambdaCallOp; } - - } else return Error(E); - if (This && !This->checkSubobject(Info, E, CSK_This)) - return false; - - // DR1358 allows virtual constexpr functions in some cases. Don't allow - // calls to such functions in constant expressions. - if (This && !HasQualifier && - isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual()) - return Error(E, diag::note_constexpr_virtual_call); + SmallVector<QualType, 4> CovariantAdjustmentPath; + if (This) { + auto *NamedMember = dyn_cast<CXXMethodDecl>(FD); + if (NamedMember && NamedMember->isVirtual() && !HasQualifier) { + // Perform virtual dispatch, if necessary. + FD = HandleVirtualDispatch(Info, E, *This, NamedMember, + CovariantAdjustmentPath); + if (!FD) + return false; + } else { + // Check that the 'this' pointer points to an object of the right type. + if (!checkNonVirtualMemberCallThisPointer(Info, E, *This)) + return false; + } + } const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); @@ -4991,6 +6205,11 @@ public: Result, ResultSlot)) return false; + if (!CovariantAdjustmentPath.empty() && + !HandleCovariantReturnAdjustment(Info, E, Result, + CovariantAdjustmentPath)) + return false; + return true; } @@ -5016,6 +6235,8 @@ public: /// A member expression where the object is a prvalue is itself a prvalue. bool VisitMemberExpr(const MemberExpr *E) { + assert(!Info.Ctx.getLangOpts().CPlusPlus11 && + "missing temporary materialization conversion"); assert(!E->isArrow() && "missing call to bound member function?"); APValue Val; @@ -5030,7 +6251,10 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - CompleteObject Obj(&Val, BaseTy, true); + // Note: there is no lvalue base here. But this case should only ever + // happen in C or in C++98, where we cannot be evaluating a constexpr + // constructor, which is the only case the base matters. + CompleteObject Obj(APValue::LValueBase(), &Val, BaseTy); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); @@ -5069,6 +6293,14 @@ public: return false; return DerivedSuccess(RVal, E); } + case CK_LValueToRValueBitCast: { + APValue DestValue, SourceValue; + if (!Evaluate(SourceValue, Info, E->getSubExpr())) + return false; + if (!handleLValueToRValueBitCast(Info, DestValue, SourceValue, E)) + return false; + return DerivedSuccess(DestValue, E); + } } return Error(E); @@ -5274,13 +6506,13 @@ public: // - Literals // * CompoundLiteralExpr in C (and in global scope in C++) // * StringLiteral -// * CXXTypeidExpr // * PredefinedExpr // * ObjCStringLiteralExpr // * ObjCEncodeExpr // * AddrLabelExpr // * BlockExpr // * CallExpr for a MakeStringConstant builtin +// - typeid(T) expressions, as TypeInfoLValues // - Locals and temporaries // * MaterializeTemporaryExpr // * Any Expr, with a CallIndex indicating the function in which the temporary @@ -5338,6 +6570,11 @@ public: if (!Visit(E->getSubExpr())) return false; return HandleBaseToDerivedCast(Info, E, Result); + + case CK_Dynamic: + if (!Visit(E->getSubExpr())) + return false; + return HandleDynamicCast(Info, cast<ExplicitCastExpr>(E), Result); } } }; @@ -5427,7 +6664,9 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { APValue *V; if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr)) return false; - if (V->isUninit()) { + if (!V->hasValue()) { + // FIXME: Is it possible for V to be indeterminate here? If so, we should + // adjust the diagnostic to say that. if (!Info.checkingPotentialConstantExpression()) Info.FFDiag(E, diag::note_constexpr_use_uninit_reference); return false; @@ -5510,13 +6749,33 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { } bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { - if (!E->isPotentiallyEvaluated()) - return Success(E); + TypeInfoLValue TypeInfo; - Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic) - << E->getExprOperand()->getType() - << E->getExprOperand()->getSourceRange(); - return false; + if (!E->isPotentiallyEvaluated()) { + if (E->isTypeOperand()) + TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr()); + else + TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr()); + } else { + if (!Info.Ctx.getLangOpts().CPlusPlus2a) { + Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + } + + if (!Visit(E->getExprOperand())) + return false; + + Optional<DynamicType> DynType = + ComputeDynamicType(Info, E, Result, AK_TypeId); + if (!DynType) + return false; + + TypeInfo = + TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr()); + } + + return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType())); } bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { @@ -5634,6 +6893,10 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { if (!Evaluate(NewVal, this->Info, E->getRHS())) return false; + if (Info.getLangOpts().CPlusPlus2a && + !HandleUnionActiveMemberChange(Info, E->getLHS(), Result)) + return false; + return handleAssignment(this->Info, E, Result, E->getLHS()->getType(), NewVal); } @@ -5783,6 +7046,8 @@ public: bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { + if (E->isExpressibleAsConstantInitializer()) + return Success(E); if (Info.noteFailure()) EvaluateIgnoredValue(Info, E->getSubExpr()); return Error(E); @@ -5832,6 +7097,14 @@ public: return true; } + bool VisitSourceLocExpr(const SourceLocExpr *E) { + assert(E->isStringType() && "SourceLocExpr isn't a pointer type?"); + APValue LValResult = E->EvaluateInContext( + Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr()); + Result.setFrom(Info.Ctx, LValResult); + return true; + } + // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace @@ -5877,7 +7150,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: break; - case CK_BitCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: @@ -5920,6 +7192,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { return true; return HandleBaseToDerivedCast(Info, E, Result); + case CK_Dynamic: + if (!Visit(E->getSubExpr())) + return false; + return HandleDynamicCast(Info, cast<ExplicitCastExpr>(E), Result); + case CK_NullToPointer: VisitIgnoredValue(E->getSubExpr()); return ZeroInitialization(E); @@ -6092,9 +7369,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (const ValueDecl *VD = OffsetResult.Base.dyn_cast<const ValueDecl*>()) { BaseAlignment = Info.Ctx.getDeclAlign(VD); + } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) { + BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf); } else { - BaseAlignment = GetAlignOfExpr( - Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf); + BaseAlignment = GetAlignOfType( + Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf); } if (BaseAlignment < Align) { @@ -6622,6 +7901,12 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); + auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); + + EvalInfo::EvaluatingConstructorRAII EvalObj( + Info, + ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries}, + CXXRD && CXXRD->getNumBases()); if (RD->isUnion()) { const FieldDecl *Field = E->getInitializedFieldInUnion(); @@ -6648,15 +7933,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } - auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); - if (Result.isUninit()) + if (!Result.hasValue()) Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0, std::distance(RD->field_begin(), RD->field_end())); unsigned ElementNo = 0; bool Success = true; // Initialize base classes. - if (CXXRD) { + if (CXXRD && CXXRD->getNumBases()) { for (const auto &Base : CXXRD->bases()) { assert(ElementNo < E->getNumInits() && "missing init for base class"); const Expr *Init = E->getInit(ElementNo); @@ -6673,6 +7957,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } ++ElementNo; } + + EvalObj.finishedConstructingBases(); } // Initialize members. @@ -6724,7 +8010,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, bool ZeroInit = E->requiresZeroInitialization(); if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { // If we've already performed zero-initialization, we're already done. - if (!Result.isUninit()) + if (Result.hasValue()) return true; // We can get here in two different ways: @@ -7130,8 +8416,7 @@ namespace { : ExprEvaluatorBaseTy(Info), This(This), Result(Result) {} bool Success(const APValue &V, const Expr *E) { - assert((V.isArray() || V.isLValue()) && - "expected array or string literal"); + assert(V.isArray() && "expected array"); Result = V; return true; } @@ -7162,6 +8447,10 @@ namespace { bool VisitCXXConstructExpr(const CXXConstructExpr *E, const LValue &Subobject, APValue *Value, QualType Type); + bool VisitStringLiteral(const StringLiteral *E) { + expandStringLiteral(Info, E, Result); + return true; + } }; } // end anonymous namespace @@ -7194,14 +8483,8 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...] // an appropriately-typed string literal enclosed in braces. - if (E->isStringLiteralInit()) { - LValue LV; - if (!EvaluateLValue(E->getInit(0), LV, Info)) - return false; - APValue Val; - LV.moveInto(Val); - return Success(Val, E); - } + if (E->isStringLiteralInit()) + return Visit(E->getInit(0)); bool Success = true; @@ -7227,7 +8510,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // If the array was previously zero-initialized, preserve the // zero-initialized values. - if (!Filler.isUninit()) { + if (Filler.hasValue()) { for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I) Result.getArrayInitializedElt(I) = Filler; if (Result.hasArrayFiller()) @@ -7296,7 +8579,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, const LValue &Subobject, APValue *Value, QualType Type) { - bool HadZeroInit = !Value->isUninit(); + bool HadZeroInit = Value->hasValue(); if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { unsigned N = CAT->getSize().getZExtValue(); @@ -7391,7 +8674,7 @@ public: } bool Success(const APValue &V, const Expr *E) { - if (V.isLValue() || V.isAddrLabelDiff()) { + if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) { Result = V; return true; } @@ -7478,7 +8761,7 @@ public: bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); - + bool VisitSourceLocExpr(const SourceLocExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; @@ -7490,53 +8773,27 @@ class FixedPointExprEvaluator FixedPointExprEvaluator(EvalInfo &info, APValue &result) : ExprEvaluatorBaseTy(info), Result(result) {} - bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { - assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); - assert(SI.isSigned() == E->getType()->isSignedFixedPointType() && - "Invalid evaluation result."); - assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && - "Invalid evaluation result."); - Result = APValue(SI); - return true; - } - bool Success(const llvm::APSInt &SI, const Expr *E) { - return Success(SI, E, Result); - } - - bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { - assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); - assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && - "Invalid evaluation result."); - Result = APValue(APSInt(I)); - Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType()); - return true; - } bool Success(const llvm::APInt &I, const Expr *E) { - return Success(I, E, Result); + return Success( + APFixedPoint(I, Info.Ctx.getFixedPointSemantics(E->getType())), E); } - bool Success(uint64_t Value, const Expr *E, APValue &Result) { - assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); - Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); - return true; - } bool Success(uint64_t Value, const Expr *E) { - return Success(Value, E, Result); - } - - bool Success(CharUnits Size, const Expr *E) { - return Success(Size.getQuantity(), E); + return Success( + APFixedPoint(Value, Info.Ctx.getFixedPointSemantics(E->getType())), E); } bool Success(const APValue &V, const Expr *E) { - if (V.isLValue() || V.isAddrLabelDiff()) { - Result = V; - return true; - } - return Success(V.getInt(), E); + return Success(V.getFixedPoint(), E); } - bool ZeroInitialization(const Expr *E) { return Success(0, E); } + bool Success(const APFixedPoint &V, const Expr *E) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(V.getWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(V); + return true; + } //===--------------------------------------------------------------------===// // Visitor Methods @@ -7546,7 +8803,9 @@ class FixedPointExprEvaluator return Success(E->getValue(), E); } + bool VisitCastExpr(const CastExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitBinaryOperator(const BinaryOperator *E); }; } // end anonymous namespace @@ -7578,6 +8837,42 @@ static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info) { return true; } +bool IntExprEvaluator::VisitSourceLocExpr(const SourceLocExpr *E) { + APValue Evaluated = E->EvaluateInContext( + Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr()); + return Success(Evaluated, E); +} + +static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result, + EvalInfo &Info) { + if (E->getType()->isFixedPointType()) { + APValue Val; + if (!FixedPointExprEvaluator(Info, Val).Visit(E)) + return false; + if (!Val.isFixedPoint()) + return false; + + Result = Val.getFixedPoint(); + return true; + } + return false; +} + +static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, + EvalInfo &Info) { + if (E->getType()->isIntegerType()) { + auto FXSema = Info.Ctx.getFixedPointSemantics(E->getType()); + APSInt Val; + if (!EvaluateInteger(E, Val, Info)) + return false; + Result = APFixedPoint(Val, FXSema); + return true; + } else if (E->getType()->isFixedPointType()) { + return EvaluateFixedPoint(E, Result, Info); + } + return false; +} + /// Check whether the given declaration can be directly converted to an integral /// rvalue. If not, no diagnostic is produced; there are other things we can /// try. @@ -7783,19 +9078,41 @@ EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) { } /// EvaluateBuiltinConstantPForLValue - Determine the result of -/// __builtin_constant_p when applied to the given lvalue. +/// __builtin_constant_p when applied to the given pointer. /// -/// An lvalue is only "constant" if it is a pointer or reference to the first -/// character of a string literal. -template<typename LValue> -static bool EvaluateBuiltinConstantPForLValue(const LValue &LV) { - const Expr *E = LV.getLValueBase().template dyn_cast<const Expr*>(); - return E && isa<StringLiteral>(E) && LV.getLValueOffset().isZero(); +/// A pointer is only "constant" if it is null (or a pointer cast to integer) +/// or it points to the first character of a string literal. +static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) { + APValue::LValueBase Base = LV.getLValueBase(); + if (Base.isNull()) { + // A null base is acceptable. + return true; + } else if (const Expr *E = Base.dyn_cast<const Expr *>()) { + if (!isa<StringLiteral>(E)) + return false; + return LV.getLValueOffset().isZero(); + } else if (Base.is<TypeInfoLValue>()) { + // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to + // evaluate to true. + return true; + } else { + // Any other base is not constant enough for GCC. + return false; + } } /// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to /// GCC as we can manage. -static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { +static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) { + // This evaluation is not permitted to have side-effects, so evaluate it in + // a speculative evaluation context. + SpeculativeEvaluationRAII SpeculativeEval(Info); + + // Constant-folding is always enabled for the operand of __builtin_constant_p + // (even when the enclosing evaluation context otherwise requires a strict + // language-specific constant expression). + FoldConstant Fold(Info, true); + QualType ArgType = Arg->getType(); // __builtin_constant_p always has one operand. The rules which gcc follows @@ -7803,34 +9120,30 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { // // - If the operand is of integral, floating, complex or enumeration type, // and can be folded to a known value of that type, it returns 1. - // - If the operand and can be folded to a pointer to the first character - // of a string literal (or such a pointer cast to an integral type), it - // returns 1. + // - If the operand can be folded to a pointer to the first character + // of a string literal (or such a pointer cast to an integral type) + // or to a null pointer or an integer cast to a pointer, it returns 1. // // Otherwise, it returns 0. // // FIXME: GCC also intends to return 1 for literals of aggregate types, but - // its support for this does not currently work. - if (ArgType->isIntegralOrEnumerationType()) { - Expr::EvalResult Result; - if (!Arg->EvaluateAsRValue(Result, Ctx) || Result.HasSideEffects) + // its support for this did not work prior to GCC 9 and is not yet well + // understood. + if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() || + ArgType->isAnyComplexType() || ArgType->isPointerType() || + ArgType->isNullPtrType()) { + APValue V; + if (!::EvaluateAsRValue(Info, Arg, V)) { + Fold.keepDiagnostics(); return false; + } - APValue &V = Result.Val; - if (V.getKind() == APValue::Int) - return true; + // For a pointer (possibly cast to integer), there are special rules. if (V.getKind() == APValue::LValue) return EvaluateBuiltinConstantPForLValue(V); - } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) { - return Arg->isEvaluatable(Ctx); - } else if (ArgType->isPointerType() || Arg->isGLValue()) { - LValue LV; - Expr::EvalStatus Status; - EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); - if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info) - : EvaluatePointer(Arg, LV, Info)) && - !Status.HasSideEffects) - return EvaluateBuiltinConstantPForLValue(LV); + + // Otherwise, any constant value is good enough. + return V.hasValue(); } // Anything else isn't considered to be sufficiently constant. @@ -7846,6 +9159,8 @@ static QualType getObjectType(APValue::LValueBase B) { } else if (const Expr *E = B.get<const Expr*>()) { if (isa<CompoundLiteralExpr>(E)) return E->getType(); + } else if (B.is<TypeInfoLValue>()) { + return B.getTypeInfoType(); } return QualType(); @@ -7940,13 +9255,13 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { if (I + 1 == E) return true; const auto *CAT = cast<ConstantArrayType>(Ctx.getAsArrayType(BaseType)); - uint64_t Index = Entry.ArrayIndex; + uint64_t Index = Entry.getAsArrayIndex(); if (Index + 1 != CAT->getSize()) return false; BaseType = CAT->getElementType(); } else if (BaseType->isAnyComplexType()) { const auto *CT = BaseType->castAs<ComplexType>(); - uint64_t Index = Entry.ArrayIndex; + uint64_t Index = Entry.getAsArrayIndex(); if (Index != 1) return false; BaseType = CT->getElementType(); @@ -8088,7 +9403,7 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, if (Designator.MostDerivedIsArrayElement && Designator.Entries.size() == Designator.MostDerivedPathLength) { uint64_t ArraySize = Designator.getMostDerivedArraySize(); - uint64_t ArrayIndex = Designator.Entries.back().ArrayIndex; + uint64_t ArrayIndex = Designator.Entries.back().getAsArrayIndex(); ElemsRemaining = ArraySize <= ArrayIndex ? 0 : ArraySize - ArrayIndex; } else { ElemsRemaining = Designator.isOnePastTheEnd() ? 0 : 1; @@ -8148,6 +9463,8 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, bool IntExprEvaluator::VisitConstantExpr(const ConstantExpr *E) { llvm::SaveAndRestore<bool> InConstantContext(Info.InConstantContext, true); + if (E->getResultAPValueKind() != APValue::None) + return Success(E->getAPValueResult(), E); return ExprEvaluatorBaseTy::VisitConstantExpr(E); } @@ -8164,6 +9481,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, default: return ExprEvaluatorBaseTy::VisitCallExpr(E); + case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: { // The type was checked when we built the expression. unsigned Type = @@ -8239,20 +9557,22 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } case Builtin::BI__builtin_constant_p: { - auto Arg = E->getArg(0); - if (EvaluateBuiltinConstantP(Info.Ctx, Arg)) + const Expr *Arg = E->getArg(0); + if (EvaluateBuiltinConstantP(Info, Arg)) return Success(true, E); - auto ArgTy = Arg->IgnoreImplicit()->getType(); - if (!Info.InConstantContext && !Arg->HasSideEffects(Info.Ctx) && - !ArgTy->isAggregateType() && !ArgTy->isPointerType()) { - // We can delay calculation of __builtin_constant_p until after - // inlining. Note: This diagnostic won't be shown to the user. - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.InConstantContext || Arg->HasSideEffects(Info.Ctx)) { + // Outside a constant context, eagerly evaluate to false in the presence + // of side-effects in order to avoid -Wunsequenced false-positives in + // a branch on __builtin_constant_p(expr). + return Success(false, E); } - return Success(false, E); + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; } + case Builtin::BI__builtin_is_constant_evaluated: + return Success(Info.InConstantContext, E); + case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: @@ -8411,6 +9731,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIstrncmp: case Builtin::BIwcsncmp: case Builtin::BImemcmp: + case Builtin::BIbcmp: case Builtin::BIwmemcmp: // A call to strlen is not a constant expression. if (Info.getLangOpts().CPlusPlus11) @@ -8425,6 +9746,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_strncmp: case Builtin::BI__builtin_wcsncmp: case Builtin::BI__builtin_memcmp: + case Builtin::BI__builtin_bcmp: case Builtin::BI__builtin_wmemcmp: { LValue String1, String2; if (!EvaluatePointer(E->getArg(0), String1, Info) || @@ -8455,7 +9777,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, QualType CharTy2 = String2.Designator.getType(Info.Ctx); bool IsRawByte = BuiltinOp == Builtin::BImemcmp || - BuiltinOp == Builtin::BI__builtin_memcmp; + BuiltinOp == Builtin::BIbcmp || + BuiltinOp == Builtin::BI__builtin_memcmp || + BuiltinOp == Builtin::BI__builtin_bcmp; assert(IsRawByte || (Info.Ctx.hasSameUnqualifiedType( @@ -8523,10 +9847,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(0, E); } - bool StopAtNull = (BuiltinOp != Builtin::BImemcmp && - BuiltinOp != Builtin::BIwmemcmp && - BuiltinOp != Builtin::BI__builtin_memcmp && - BuiltinOp != Builtin::BI__builtin_wmemcmp); + bool StopAtNull = + (BuiltinOp != Builtin::BImemcmp && BuiltinOp != Builtin::BIbcmp && + BuiltinOp != Builtin::BIwmemcmp && + BuiltinOp != Builtin::BI__builtin_memcmp && + BuiltinOp != Builtin::BI__builtin_bcmp && + BuiltinOp != Builtin::BI__builtin_wmemcmp); bool IsWide = BuiltinOp == Builtin::BIwcscmp || BuiltinOp == Builtin::BIwcsncmp || BuiltinOp == Builtin::BIwmemcmp || @@ -8654,10 +9980,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (IsSigned && !AllSigned) ++MaxBits; - LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), - !IsSigned); - RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), - !IsSigned); + LHS = APSInt(LHS.extOrTrunc(MaxBits), !IsSigned); + RHS = APSInt(RHS.extOrTrunc(MaxBits), !IsSigned); Result = APSInt(MaxBits, !IsSigned); } @@ -9123,6 +10447,22 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, return Success(CCR::Equal, E); } + if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) { + APFixedPoint LHSFX(Info.Ctx.getFixedPointSemantics(LHSTy)); + APFixedPoint RHSFX(Info.Ctx.getFixedPointSemantics(RHSTy)); + + bool LHSOK = EvaluateFixedPointOrInteger(E->getLHS(), LHSFX, Info); + if (!LHSOK && !Info.noteFailure()) + return false; + if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK) + return false; + if (LHSFX < RHSFX) + return Success(CCR::Less, E); + if (LHSFX > RHSFX) + return Success(CCR::Greater, E); + return Success(CCR::Equal, E); + } + if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { ComplexValue LHS, RHS; bool LHSOK; @@ -9739,6 +11079,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AddressSpaceConversion: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_IntegralToFixedPoint: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -9755,6 +11096,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_LValueToRValue: case CK_AtomicToNonAtomic: case CK_NoOp: + case CK_LValueToRValueBitCast: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: @@ -9773,12 +11115,25 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Success(IntResult, E); } + case CK_FixedPointToIntegral: { + APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SrcType)); + if (!EvaluateFixedPoint(SubExpr, Src, Info)) + return false; + bool Overflowed; + llvm::APSInt Result = Src.convertToInt( + Info.Ctx.getIntWidth(DestType), + DestType->isSignedIntegerOrEnumerationType(), &Overflowed); + if (Overflowed && !HandleOverflow(Info, E, Result, DestType)) + return false; + return Success(Result, E); + } + case CK_FixedPointToBoolean: { // Unsigned padding does not affect this. APValue Val; if (!Evaluate(Val, Info, SubExpr)) return false; - return Success(Val.getInt().getBoolValue(), E); + return Success(Val.getFixedPoint().getBoolValue(), E); } case CK_IntegralCast: { @@ -9821,13 +11176,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return true; } - uint64_t V; - if (LV.isNullPointer()) - V = Info.Ctx.getTargetNullPointerValue(SrcType); - else - V = LV.getLValueOffset().getQuantity(); + APSInt AsInt; + APValue V; + LV.moveInto(V); + if (!V.toIntegralConstant(AsInt, SrcType, Info.Ctx)) + llvm_unreachable("Can't cast this!"); - APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType); return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E); } @@ -9898,16 +11252,13 @@ bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); case UO_Minus: { if (!Visit(E->getSubExpr())) return false; - if (!Result.isInt()) return Error(E); - const APSInt &Value = Result.getInt(); - if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) { - SmallString<64> S; - FixedPointValueToString(S, Value, - Info.Ctx.getTypeInfo(E->getType()).Width); - Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType(); - if (Info.noteUndefinedBehavior()) return false; - } - return Success(-Value, E); + if (!Result.isFixedPoint()) + return Error(E); + bool Overflowed; + APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed); + if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType())) + return false; + return Success(Negated, E); } case UO_LNot: { bool bres; @@ -9918,6 +11269,75 @@ bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { } } +bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); + QualType DestType = E->getType(); + assert(DestType->isFixedPointType() && + "Expected destination type to be a fixed point type"); + auto DestFXSema = Info.Ctx.getFixedPointSemantics(DestType); + + switch (E->getCastKind()) { + case CK_FixedPointCast: { + APFixedPoint Src(Info.Ctx.getFixedPointSemantics(SubExpr->getType())); + if (!EvaluateFixedPoint(SubExpr, Src, Info)) + return false; + bool Overflowed; + APFixedPoint Result = Src.convert(DestFXSema, &Overflowed); + if (Overflowed && !HandleOverflow(Info, E, Result, DestType)) + return false; + return Success(Result, E); + } + case CK_IntegralToFixedPoint: { + APSInt Src; + if (!EvaluateInteger(SubExpr, Src, Info)) + return false; + + bool Overflowed; + APFixedPoint IntResult = APFixedPoint::getFromIntValue( + Src, Info.Ctx.getFixedPointSemantics(DestType), &Overflowed); + + if (Overflowed && !HandleOverflow(Info, E, IntResult, DestType)) + return false; + + return Success(IntResult, E); + } + case CK_NoOp: + case CK_LValueToRValue: + return ExprEvaluatorBaseTy::VisitCastExpr(E); + default: + return Error(E); + } +} + +bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + const Expr *LHS = E->getLHS(); + const Expr *RHS = E->getRHS(); + FixedPointSemantics ResultFXSema = + Info.Ctx.getFixedPointSemantics(E->getType()); + + APFixedPoint LHSFX(Info.Ctx.getFixedPointSemantics(LHS->getType())); + if (!EvaluateFixedPointOrInteger(LHS, LHSFX, Info)) + return false; + APFixedPoint RHSFX(Info.Ctx.getFixedPointSemantics(RHS->getType())); + if (!EvaluateFixedPointOrInteger(RHS, RHSFX, Info)) + return false; + + switch (E->getOpcode()) { + case BO_Add: { + bool AddOverflow, ConversionOverflow; + APFixedPoint Result = LHSFX.add(RHSFX, &AddOverflow) + .convert(ResultFXSema, &ConversionOverflow); + if ((AddOverflow || ConversionOverflow) && + !HandleOverflow(Info, E, Result, E->getType())) + return false; + return Success(Result, E); + } + default: + return false; + } + llvm_unreachable("Should've exited before this"); +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -10282,11 +11702,14 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_IntToOCLSampler: case CK_FixedPointCast: case CK_FixedPointToBoolean: + case CK_FixedPointToIntegral: + case CK_IntegralToFixedPoint: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: case CK_AtomicToNonAtomic: case CK_NoOp: + case CK_LValueToRValueBitCast: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_Dependent: @@ -10929,6 +12352,23 @@ static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, return true; } +static bool EvaluateAsFixedPoint(const Expr *E, Expr::EvalResult &ExprResult, + const ASTContext &Ctx, + Expr::SideEffectsKind AllowSideEffects, + EvalInfo &Info) { + if (!E->getType()->isFixedPointType()) + return false; + + if (!::EvaluateAsRValue(E, ExprResult, Ctx, Info)) + return false; + + if (!ExprResult.Val.isFixedPoint() || + hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) + return false; + + return true; +} + /// EvaluateAsRValue - Return true if this is a constant which we can fold using /// any crazy technique (that has nothing to do with language standards) that /// we want to. If this function returns true, it returns the folded constant @@ -10936,31 +12376,54 @@ static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult, /// will be applied to the result. bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); Info.InConstantContext = InConstantContext; return ::EvaluateAsRValue(this, Result, Ctx, Info); } -bool Expr::EvaluateAsBooleanCondition(bool &Result, - const ASTContext &Ctx) const { +bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, + bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); EvalResult Scratch; - return EvaluateAsRValue(Scratch, Ctx) && + return EvaluateAsRValue(Scratch, Ctx, InConstantContext) && HandleConversionToBool(Scratch.Val, Result); } bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects) const { + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + Info.InConstantContext = InConstantContext; return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info); } +bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + Info.InConstantContext = InConstantContext; + return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info); +} + bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects) const { + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + if (!getType()->isRealFloatingType()) return false; EvalResult ExprResult; - if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() || + if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) || + !ExprResult.Val.isFloat() || hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) return false; @@ -10968,9 +12431,13 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, return true; } -bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { - EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); +bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, + bool InConstantContext) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); + Info.InConstantContext = InConstantContext; LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), @@ -10984,8 +12451,13 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, const ASTContext &Ctx) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; EvalInfo Info(Ctx, Result, EM); + Info.InConstantContext = true; + if (!::Evaluate(Result.Val, Info, this)) return false; @@ -10996,6 +12468,9 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl<PartialDiagnosticAt> &Notes) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + // FIXME: Evaluating initializers for large array and record types can cause // performance problems. Only do so in C++11 for now. if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) && @@ -11038,6 +12513,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded, but discard the result. bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalResult Result; return EvaluateAsRValue(Result, Ctx, /* in constant context */ true) && !hasUnacceptableSideEffect(Result, SEK); @@ -11045,6 +12523,9 @@ bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const { APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl<PartialDiagnosticAt> *Diag) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalResult EVResult; EVResult.Diag = Diag; EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects); @@ -11060,6 +12541,9 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, APSInt Expr::EvaluateKnownConstIntCheckOverflow( const ASTContext &Ctx, SmallVectorImpl<PartialDiagnosticAt> *Diag) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + EvalResult EVResult; EVResult.Diag = Diag; EvalInfo Info(Ctx, EVResult, EvalInfo::EM_EvaluateForOverflow); @@ -11074,6 +12558,9 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow( } void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + bool IsConst; EvalResult EVResult; if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) { @@ -11244,7 +12731,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::SizeOfPackExprClass: case Expr::GNUNullExprClass: - // GCC considers the GNU __null value to be an integral constant expression. + case Expr::SourceLocExprClass: return NoDiag(); case Expr::SubstNonTypeTemplateParmExprClass: @@ -11525,6 +13012,11 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ChooseExprClass: { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx); } + case Expr::BuiltinBitCastExprClass: { + if (!checkBitCastConstexprEligibility(nullptr, Ctx, cast<CastExpr>(E))) + return ICEDiag(IK_NotICE, E->getBeginLoc()); + return CheckICE(cast<CastExpr>(E)->getSubExpr(), Ctx); + } } llvm_unreachable("Invalid StmtClass!"); @@ -11555,6 +13047,9 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + if (Ctx.getLangOpts().CPlusPlus11) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc); @@ -11568,6 +13063,9 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx, SourceLocation *Loc, bool isEvaluated) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + if (Ctx.getLangOpts().CPlusPlus11) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc); @@ -11591,11 +13089,17 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx, } bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + return CheckICE(this, Ctx).Kind == IK_ICE; } bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result, SourceLocation *Loc) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + // We support this checking in C++98 mode in order to diagnose compatibility // issues. assert(Ctx.getLangOpts().CPlusPlus); @@ -11624,8 +13128,12 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, const FunctionDecl *Callee, ArrayRef<const Expr*> Args, const Expr *This) const { + assert(!isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated); + Info.InConstantContext = true; LValue ThisVal; const LValue *ThisPtr = nullptr; @@ -11704,16 +13212,20 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E, const FunctionDecl *FD, SmallVectorImpl< PartialDiagnosticAt> &Diags) { + assert(!E->isValueDependent() && + "Expression evaluator can't be called on a dependent expression."); + Expr::EvalStatus Status; Status.Diag = &Diags; EvalInfo Info(FD->getASTContext(), Status, EvalInfo::EM_PotentialConstantExpressionUnevaluated); + Info.InConstantContext = true; // Fabricate a call stack frame to give the arguments a plausible cover story. ArrayRef<const Expr*> Args; ArgVector ArgValues(0); - bool Success = EvaluateArgs(Args, ArgValues, Info); + bool Success = EvaluateArgs(Args, ArgValues, Info, FD); (void)Success; assert(Success && "Failed to set up arguments for potential constant evaluation"); diff --git a/lib/AST/ExprObjC.cpp b/lib/AST/ExprObjC.cpp index e1a23f5985892..53d0e873f8c9e 100644 --- a/lib/AST/ExprObjC.cpp +++ b/lib/AST/ExprObjC.cpp @@ -1,9 +1,8 @@ //===- ExprObjC.cpp - (ObjC) Expression AST Node Implementation -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -293,6 +292,32 @@ void ObjCMessageExpr::getSelectorLocs( SelLocs.push_back(getSelectorLoc(i)); } + +QualType ObjCMessageExpr::getCallReturnType(ASTContext &Ctx) const { + if (const ObjCMethodDecl *MD = getMethodDecl()) { + QualType QT = MD->getReturnType(); + if (QT == Ctx.getObjCInstanceType()) { + // instancetype corresponds to expression types. + return getType(); + } + return QT; + } + + // Expression type might be different from an expected call return type, + // as expression type would never be a reference even if call returns a + // reference. Reconstruct the original expression type. + QualType QT = getType(); + switch (getValueKind()) { + case VK_LValue: + return Ctx.getLValueReferenceType(QT); + case VK_XValue: + return Ctx.getRValueReferenceType(QT); + case VK_RValue: + return QT; + } + llvm_unreachable("Unsupported ExprValueKind"); +} + SourceRange ObjCMessageExpr::getReceiverRange() const { switch (getReceiverKind()) { case Instance: @@ -352,6 +377,11 @@ Stmt::child_range ObjCMessageExpr::children() { reinterpret_cast<Stmt **>(getArgs() + getNumArgs())); } +Stmt::const_child_range ObjCMessageExpr::children() const { + auto Children = const_cast<ObjCMessageExpr *>(this)->children(); + return const_child_range(Children.begin(), Children.end()); +} + StringRef ObjCBridgedCastExpr::getBridgeKindName() const { switch (getBridgeKind()) { case OBC_Bridge: diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp index 12e6bfc041a48..61e657da7c919 100644 --- a/lib/AST/ExternalASTMerger.cpp +++ b/lib/AST/ExternalASTMerger.cpp @@ -1,9 +1,8 @@ //===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -57,7 +56,12 @@ LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC, } auto *ND = cast<NamedDecl>(DC); DeclarationName Name = ND->getDeclName(); - Source<DeclarationName> SourceName = ReverseImporter.Import(Name); + auto SourceNameOrErr = ReverseImporter.Import(Name); + if (!SourceNameOrErr) { + llvm::consumeError(SourceNameOrErr.takeError()); + return nullptr; + } + Source<DeclarationName> SourceName = *SourceNameOrErr; DeclContext::lookup_result SearchResult = SourceParentDC.get()->lookup(SourceName.get()); size_t SearchResultSize = SearchResult.size(); @@ -111,7 +115,7 @@ public: /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin /// map is kept up to date. Also set the appropriate flags. - Decl *Imported(Decl *From, Decl *To) override { + void Imported(Decl *From, Decl *To) override { if (auto *ToDC = dyn_cast<DeclContext>(To)) { const bool LoggingEnabled = Parent.LoggingEnabled(); if (LoggingEnabled) @@ -154,7 +158,6 @@ public: ToContainer->getPrimaryContext()->setMustBuildLookupTable(); assert(Parent.CanComplete(ToContainer)); } - return To; } ASTImporter &GetReverse() { return Reverse; } }; @@ -230,7 +233,7 @@ void ExternalASTMerger::CompleteType(TagDecl *Tag) { if (!SourceTag->getDefinition()) return false; Forward.MapImported(SourceTag, Tag); - if (llvm::Error Err = Forward.ImportDefinition_New(SourceTag)) + if (llvm::Error Err = Forward.ImportDefinition(SourceTag)) llvm::consumeError(std::move(Err)); Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); return true; @@ -250,7 +253,7 @@ void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { if (!SourceInterface->getDefinition()) return false; Forward.MapImported(SourceInterface, Interface); - if (llvm::Error Err = Forward.ImportDefinition_New(SourceInterface)) + if (llvm::Error Err = Forward.ImportDefinition(SourceInterface)) llvm::consumeError(std::move(Err)); return true; }); @@ -356,9 +359,13 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { template <typename DeclTy> static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { - for (auto *Spec : D->specializations()) - if (!Importer->Import(Spec)) + for (auto *Spec : D->specializations()) { + auto ImportedSpecOrError = Importer->Import(Spec); + if (!ImportedSpecOrError) { + llvm::consumeError(ImportedSpecOrError.takeError()); return true; + } + } return false; } @@ -385,15 +392,21 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, Candidates.push_back(C); }; - ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, - Source<const DeclContext *> SourceDC) -> bool { - DeclarationName FromName = Reverse.Import(Name); - DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); - for (NamedDecl *FromD : Result) { - FilterFoundDecl(std::make_pair(FromD, &Forward)); - } - return false; - }); + ForEachMatchingDC(DC, + [&](ASTImporter &Forward, ASTImporter &Reverse, + Source<const DeclContext *> SourceDC) -> bool { + auto FromNameOrErr = Reverse.Import(Name); + if (!FromNameOrErr) { + llvm::consumeError(FromNameOrErr.takeError()); + return false; + } + DeclContextLookupResult Result = + SourceDC.get()->lookup(*FromNameOrErr); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, &Forward)); + } + return false; + }); if (Candidates.empty()) return false; @@ -402,7 +415,10 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, for (const Candidate &C : Candidates) { Decl *LookupRes = C.first.get(); ASTImporter *Importer = C.second; - NamedDecl *ND = cast_or_null<NamedDecl>(Importer->Import(LookupRes)); + auto NDOrErr = Importer->Import(LookupRes); + assert(NDOrErr); + (void)static_cast<bool>(NDOrErr); + NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr); assert(ND); // If we don't import specialization, they are not available via lookup // because the lookup result is imported TemplateDecl and it does not @@ -424,9 +440,12 @@ void ExternalASTMerger::FindExternalLexicalDecls( Source<const DeclContext *> SourceDC) -> bool { for (const Decl *SourceDecl : SourceDC.get()->decls()) { if (IsKindWeWant(SourceDecl->getKind())) { - Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl)); - assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC)); - (void)ImportedDecl; + auto ImportedDeclOrErr = Forward.Import(SourceDecl); + if (ImportedDeclOrErr) + assert(!(*ImportedDeclOrErr) || + IsSameDC((*ImportedDeclOrErr)->getDeclContext(), DC)); + else + llvm::consumeError(ImportedDeclOrErr.takeError()); } } return false; diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp index 40829c2e249dd..7301027574407 100644 --- a/lib/AST/ExternalASTSource.cpp +++ b/lib/AST/ExternalASTSource.cpp @@ -1,9 +1,8 @@ //===- ExternalASTSource.cpp - Abstract External AST Interface ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/FormatString.cpp b/lib/AST/FormatString.cpp index 04bd48f14a2a0..578d5bc567338 100644 --- a/lib/AST/FormatString.cpp +++ b/lib/AST/FormatString.cpp @@ -1,9 +1,8 @@ // FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*- // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -224,6 +223,9 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, if (I != E && *I == 'h') { ++I; lmKind = LengthModifier::AsChar; + } else if (I != E && *I == 'l' && LO.OpenCL) { + ++I; + lmKind = LengthModifier::AsShortLong; } else { lmKind = LengthModifier::AsShort; } @@ -488,7 +490,8 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { } ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const { - if (K != SpecificTy) // Won't be a valid vector element type. + // Check for valid vector element types. + if (T.isNull()) return ArgType::Invalid(); QualType Vec = C.getExtVectorType(T, NumElts); @@ -573,6 +576,8 @@ analyze_format_string::LengthModifier::toString() const { return "hh"; case AsShort: return "h"; + case AsShortLong: + return "hl"; case AsLong: // or AsWideChar return "l"; case AsLongLong: @@ -708,13 +713,18 @@ void OptionalAmount::toString(raw_ostream &os) const { } } -bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { +bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target, + const LangOptions &LO) const { switch (LM.getKind()) { case LengthModifier::None: return true; // Handle most integer flags case LengthModifier::AsShort: + // Length modifier only applies to FP vectors. + if (LO.OpenCL && CS.isDoubleArg()) + return !VectorNumElts.isInvalid(); + if (Target.getTriple().isOSMSVCRT()) { switch (CS.getKind()) { case ConversionSpecifier::cArg: @@ -753,8 +763,18 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { return false; } + case LengthModifier::AsShortLong: + return LO.OpenCL && !VectorNumElts.isInvalid(); + // Handle 'l' flag case LengthModifier::AsLong: // or AsWideChar + if (CS.isDoubleArg()) { + // Invalid for OpenCL FP scalars. + if (LO.OpenCL && VectorNumElts.isInvalid()) + return false; + return true; + } + switch (CS.getKind()) { case ConversionSpecifier::dArg: case ConversionSpecifier::DArg: @@ -765,14 +785,6 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: - case ConversionSpecifier::aArg: - case ConversionSpecifier::AArg: - case ConversionSpecifier::fArg: - case ConversionSpecifier::FArg: - case ConversionSpecifier::eArg: - case ConversionSpecifier::EArg: - case ConversionSpecifier::gArg: - case ConversionSpecifier::GArg: case ConversionSpecifier::nArg: case ConversionSpecifier::cArg: case ConversionSpecifier::sArg: @@ -879,6 +891,7 @@ bool FormatSpecifier::hasStandardLengthModifier() const { case LengthModifier::AsInt3264: case LengthModifier::AsInt64: case LengthModifier::AsWide: + case LengthModifier::AsShortLong: // ??? return false; } llvm_unreachable("Invalid LengthModifier Kind!"); diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index 0b82da133fa76..4b3d5bee5631e 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -1,9 +1,8 @@ //===- InheritViz.cpp - Graphviz visualization for inheritance --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 64580edf004b6..727a905d08a14 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -1,9 +1,8 @@ //===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 98c843db31d62..6c813f09a4b3c 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1,9 +1,8 @@ //===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -61,7 +60,8 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { } const DeclContext *DC = D->getDeclContext(); - if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) { + if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) || + isa<OMPDeclareMapperDecl>(DC)) { return getEffectiveDeclContext(cast<Decl>(DC)); } @@ -486,6 +486,7 @@ private: const AbiTagList *AdditionalAbiTags); void mangleBlockForPrefix(const BlockDecl *Block); void mangleUnqualifiedBlock(const BlockDecl *Block); + void mangleTemplateParamDecl(const NamedDecl *Decl); void mangleLambda(const CXXRecordDecl *Lambda); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, @@ -537,6 +538,7 @@ private: unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); + void mangleDeclRefExpr(const NamedDecl *D); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom); void mangleCXXDtorType(CXXDtorType T); @@ -1372,7 +1374,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // <unnamed-type-name> ::= <closure-type-name> // // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ - // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. + // <lambda-sig> ::= <template-param-decl>* <parameter-type>+ + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { if (Record->isLambda() && Record->getLambdaManglingNumber()) { assert(!AdditionalAbiTags && @@ -1503,7 +1506,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { - Qualifiers MethodQuals = Method->getTypeQualifiers(); + Qualifiers MethodQuals = Method->getMethodQualifiers(); // We do not consider restrict a distinguishing attribute for overloading // purposes so we must not mangle it. MethodQuals.removeRestrict(); @@ -1678,6 +1681,24 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { Out << '_'; } +// <template-param-decl> +// ::= Ty # template type parameter +// ::= Tn <type> # template non-type parameter +// ::= Tt <template-param-decl>* E # template template parameter +void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { + if (isa<TemplateTypeParmDecl>(Decl)) { + Out << "Ty"; + } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) { + Out << "Tn"; + mangleType(Tn->getType()); + } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) { + Out << "Tt"; + for (auto *Param : *Tt->getTemplateParameters()) + mangleTemplateParamDecl(Param); + Out << "E"; + } +} + void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // If the context of a closure type is an initializer for a class member // (static or nonstatic), it is encoded in a qualified name with a final @@ -1705,6 +1726,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { } Out << "Ul"; + for (auto *D : Lambda->getLambdaExplicitTemplateParameters()) + mangleTemplateParamDecl(D); const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> getAs<FunctionProtoType>(); mangleBareFunctionType(Proto, /*MangleReturnType=*/false, @@ -1869,6 +1892,7 @@ void CXXNameMangler::mangleType(TemplateName TN) { break; case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: llvm_unreachable("can't mangle an overloaded template name as a <type>"); case TemplateName::DependentTemplate: { @@ -1941,6 +1965,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::ObjCTypeParam: case Type::Atomic: case Type::Pipe: + case Type::MacroQualified: llvm_unreachable("type is illegal as a nested name specifier"); case Type::SubstTemplateTypeParmPack: @@ -2007,6 +2032,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, } case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: case TemplateName::DependentTemplate: llvm_unreachable("invalid base for a template specialization type"); @@ -2581,17 +2607,22 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Double: Out << 'd'; break; - case BuiltinType::LongDouble: - Out << (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble() - ? 'g' - : 'e'); + case BuiltinType::LongDouble: { + const TargetInfo *TI = getASTContext().getLangOpts().OpenMP && + getASTContext().getLangOpts().OpenMPIsDevice + ? getASTContext().getAuxTargetInfo() + : &getASTContext().getTargetInfo(); + Out << TI->getLongDoubleMangling(); break; - case BuiltinType::Float128: - if (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble()) - Out << "U10__float128"; // Match the GCC mangling - else - Out << 'g'; + } + case BuiltinType::Float128: { + const TargetInfo *TI = getASTContext().getLangOpts().OpenMP && + getASTContext().getLangOpts().OpenMPIsDevice + ? getASTContext().getAuxTargetInfo() + : &getASTContext().getTargetInfo(); + Out << TI->getFloat128Mangling(); break; + } case BuiltinType::NullPtr: Out << "Dn"; break; @@ -2735,7 +2766,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { // Mangle CV-qualifiers, if present. These are 'this' qualifiers, // e.g. "const" in "int (A::*)() const". - mangleQualifiers(T->getTypeQuals()); + mangleQualifiers(T->getMethodQuals()); // Mangle instantiation-dependent exception-specification, if present, // per cxx-abi-dev proposal on 2016-10-11. @@ -2833,7 +2864,10 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto, if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) { // Attr can only take 1 character, so we can hardcode the length below. assert(Attr->getType() <= 9 && Attr->getType() >= 0); - Out << "U17pass_object_size" << Attr->getType(); + if (Attr->isDynamic()) + Out << "U25pass_dynamic_object_size" << Attr->getType(); + else + Out << "U17pass_object_size" << Attr->getType(); } } } @@ -3471,6 +3505,32 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) { mangleExpression(InitList->getInit(i)); } +void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) { + switch (D->getKind()) { + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D); + Out << 'E'; + break; + + case Decl::ParmVar: + mangleFunctionParam(cast<ParmVarDecl>(D)); + break; + + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + + case Decl::NonTypeTemplateParm: + const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); + mangleTemplateParameter(PD->getIndex()); + break; + } +} + void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> @@ -3561,7 +3621,9 @@ recurse: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: + case Expr::SourceLocExprClass: case Expr::FixedPointLiteralClass: + case Expr::BuiltinBitCastExprClass: { if (!NullOut) { // As bad as this diagnostic is, it's better than crashing. @@ -3725,7 +3787,7 @@ recurse: if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { if (Qualifier) { mangleUnresolvedPrefix(Qualifier, - /*Recursive=*/true); + /*recursive=*/true); mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType()); Out << 'E'; } else { @@ -3896,7 +3958,7 @@ recurse: Diags.Report(DiagID); return; } - case UETT_OpenMPRequiredSimdAlign: + case UETT_OpenMPRequiredSimdAlign: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, @@ -3904,6 +3966,7 @@ recurse: Diags.Report(DiagID); return; } + } if (SAE->isArgumentType()) { Out << 't'; mangleType(SAE->getArgumentType()); @@ -4060,37 +4123,9 @@ recurse: mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); break; - case Expr::DeclRefExprClass: { - const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); - - switch (D->getKind()) { - default: - // <expr-primary> ::= L <mangled-name> E # external name - Out << 'L'; - mangle(D); - Out << 'E'; - break; - - case Decl::ParmVar: - mangleFunctionParam(cast<ParmVarDecl>(D)); - break; - - case Decl::EnumConstant: { - const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); - mangleIntegerLiteral(ED->getType(), ED->getInitVal()); - break; - } - - case Decl::NonTypeTemplateParm: { - const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); - mangleTemplateParameter(PD->getIndex()); - break; - } - - } - + case Expr::DeclRefExprClass: + mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl()); break; - } case Expr::SubstNonTypeTemplateParmPackExprClass: // FIXME: not clear how to mangle this! @@ -4104,7 +4139,7 @@ recurse: // FIXME: not clear how to mangle this! const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); Out << "v110_SUBSTPACK"; - mangleFunctionParam(FPPE->getParameterPack()); + mangleDeclRefExpr(FPPE->getParameterPack()); break; } @@ -4454,7 +4489,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // It's possible to end up with a DeclRefExpr here in certain // dependent cases, in which case we should mangle as a // declaration. - const Expr *E = A.getAsExpr()->IgnoreParens(); + const Expr *E = A.getAsExpr()->IgnoreParenImpCasts(); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { const ValueDecl *D = DRE->getDecl(); if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) { diff --git a/lib/AST/JSONNodeDumper.cpp b/lib/AST/JSONNodeDumper.cpp new file mode 100644 index 0000000000000..04b933b0fb306 --- /dev/null +++ b/lib/AST/JSONNodeDumper.cpp @@ -0,0 +1,1569 @@ +#include "clang/AST/JSONNodeDumper.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +void JSONNodeDumper::addPreviousDeclaration(const Decl *D) { + switch (D->getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: \ + return writePreviousDeclImpl(cast<DERIVED##Decl>(D)); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" +#undef ABSTRACT_DECL +#undef DECL + } + llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); +} + +void JSONNodeDumper::Visit(const Attr *A) { + const char *AttrName = nullptr; + switch (A->getKind()) { +#define ATTR(X) \ + case attr::X: \ + AttrName = #X"Attr"; \ + break; +#include "clang/Basic/AttrList.inc" +#undef ATTR + } + JOS.attribute("id", createPointerRepresentation(A)); + JOS.attribute("kind", AttrName); + JOS.attributeObject("range", [A, this] { writeSourceRange(A->getRange()); }); + attributeOnlyIfTrue("inherited", A->isInherited()); + attributeOnlyIfTrue("implicit", A->isImplicit()); + + // FIXME: it would be useful for us to output the spelling kind as well as + // the actual spelling. This would allow us to distinguish between the + // various attribute syntaxes, but we don't currently track that information + // within the AST. + //JOS.attribute("spelling", A->getSpelling()); + + InnerAttrVisitor::Visit(A); +} + +void JSONNodeDumper::Visit(const Stmt *S) { + if (!S) + return; + + JOS.attribute("id", createPointerRepresentation(S)); + JOS.attribute("kind", S->getStmtClassName()); + JOS.attributeObject("range", + [S, this] { writeSourceRange(S->getSourceRange()); }); + + if (const auto *E = dyn_cast<Expr>(S)) { + JOS.attribute("type", createQualType(E->getType())); + const char *Category = nullptr; + switch (E->getValueKind()) { + case VK_LValue: Category = "lvalue"; break; + case VK_XValue: Category = "xvalue"; break; + case VK_RValue: Category = "rvalue"; break; + } + JOS.attribute("valueCategory", Category); + } + InnerStmtVisitor::Visit(S); +} + +void JSONNodeDumper::Visit(const Type *T) { + JOS.attribute("id", createPointerRepresentation(T)); + JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str()); + JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false)); + attributeOnlyIfTrue("isDependent", T->isDependentType()); + attributeOnlyIfTrue("isInstantiationDependent", + T->isInstantiationDependentType()); + attributeOnlyIfTrue("isVariablyModified", T->isVariablyModifiedType()); + attributeOnlyIfTrue("containsUnexpandedPack", + T->containsUnexpandedParameterPack()); + attributeOnlyIfTrue("isImported", T->isFromAST()); + InnerTypeVisitor::Visit(T); +} + +void JSONNodeDumper::Visit(QualType T) { + JOS.attribute("id", createPointerRepresentation(T.getAsOpaquePtr())); + JOS.attribute("kind", "QualType"); + JOS.attribute("type", createQualType(T)); + JOS.attribute("qualifiers", T.split().Quals.getAsString()); +} + +void JSONNodeDumper::Visit(const Decl *D) { + JOS.attribute("id", createPointerRepresentation(D)); + + if (!D) + return; + + JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str()); + JOS.attributeObject("loc", + [D, this] { writeSourceLocation(D->getLocation()); }); + JOS.attributeObject("range", + [D, this] { writeSourceRange(D->getSourceRange()); }); + attributeOnlyIfTrue("isImplicit", D->isImplicit()); + attributeOnlyIfTrue("isInvalid", D->isInvalidDecl()); + + if (D->isUsed()) + JOS.attribute("isUsed", true); + else if (D->isThisDeclarationReferenced()) + JOS.attribute("isReferenced", true); + + if (const auto *ND = dyn_cast<NamedDecl>(D)) + attributeOnlyIfTrue("isHidden", ND->isHidden()); + + if (D->getLexicalDeclContext() != D->getDeclContext()) + JOS.attribute("parentDeclContext", + createPointerRepresentation(D->getDeclContext())); + + addPreviousDeclaration(D); + InnerDeclVisitor::Visit(D); +} + +void JSONNodeDumper::Visit(const comments::Comment *C, + const comments::FullComment *FC) { + if (!C) + return; + + JOS.attribute("id", createPointerRepresentation(C)); + JOS.attribute("kind", C->getCommentKindName()); + JOS.attributeObject("loc", + [C, this] { writeSourceLocation(C->getLocation()); }); + JOS.attributeObject("range", + [C, this] { writeSourceRange(C->getSourceRange()); }); + + InnerCommentVisitor::visit(C, FC); +} + +void JSONNodeDumper::Visit(const TemplateArgument &TA, SourceRange R, + const Decl *From, StringRef Label) { + JOS.attribute("kind", "TemplateArgument"); + if (R.isValid()) + JOS.attributeObject("range", [R, this] { writeSourceRange(R); }); + + if (From) + JOS.attribute(Label.empty() ? "fromDecl" : Label, createBareDeclRef(From)); + + InnerTemplateArgVisitor::Visit(TA); +} + +void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) { + JOS.attribute("kind", "CXXCtorInitializer"); + if (Init->isAnyMemberInitializer()) + JOS.attribute("anyInit", createBareDeclRef(Init->getAnyMember())); + else if (Init->isBaseInitializer()) + JOS.attribute("baseInit", + createQualType(QualType(Init->getBaseClass(), 0))); + else if (Init->isDelegatingInitializer()) + JOS.attribute("delegatingInit", + createQualType(Init->getTypeSourceInfo()->getType())); + else + llvm_unreachable("Unknown initializer type"); +} + +void JSONNodeDumper::Visit(const OMPClause *C) {} + +void JSONNodeDumper::Visit(const BlockDecl::Capture &C) { + JOS.attribute("kind", "Capture"); + attributeOnlyIfTrue("byref", C.isByRef()); + attributeOnlyIfTrue("nested", C.isNested()); + if (C.getVariable()) + JOS.attribute("var", createBareDeclRef(C.getVariable())); +} + +void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) { + JOS.attribute("associationKind", A.getTypeSourceInfo() ? "case" : "default"); + attributeOnlyIfTrue("selected", A.isSelected()); +} + +void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc, + bool IsSpelling) { + PresumedLoc Presumed = SM.getPresumedLoc(Loc); + unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc) + : SM.getExpansionLineNumber(Loc); + if (Presumed.isValid()) { + if (LastLocFilename != Presumed.getFilename()) { + JOS.attribute("file", Presumed.getFilename()); + JOS.attribute("line", ActualLine); + } else if (LastLocLine != ActualLine) + JOS.attribute("line", ActualLine); + + unsigned PresumedLine = Presumed.getLine(); + if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine) + JOS.attribute("presumedLine", PresumedLine); + + JOS.attribute("col", Presumed.getColumn()); + JOS.attribute("tokLen", + Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts())); + LastLocFilename = Presumed.getFilename(); + LastLocPresumedLine = PresumedLine; + LastLocLine = ActualLine; + } +} + +void JSONNodeDumper::writeSourceLocation(SourceLocation Loc) { + SourceLocation Spelling = SM.getSpellingLoc(Loc); + SourceLocation Expansion = SM.getExpansionLoc(Loc); + + if (Expansion != Spelling) { + // If the expansion and the spelling are different, output subobjects + // describing both locations. + JOS.attributeObject("spellingLoc", [Spelling, this] { + writeBareSourceLocation(Spelling, /*IsSpelling*/ true); + }); + JOS.attributeObject("expansionLoc", [Expansion, Loc, this] { + writeBareSourceLocation(Expansion, /*IsSpelling*/ false); + // If there is a macro expansion, add extra information if the interesting + // bit is the macro arg expansion. + if (SM.isMacroArgExpansion(Loc)) + JOS.attribute("isMacroArgExpansion", true); + }); + } else + writeBareSourceLocation(Spelling, /*IsSpelling*/ true); +} + +void JSONNodeDumper::writeSourceRange(SourceRange R) { + JOS.attributeObject("begin", + [R, this] { writeSourceLocation(R.getBegin()); }); + JOS.attributeObject("end", [R, this] { writeSourceLocation(R.getEnd()); }); +} + +std::string JSONNodeDumper::createPointerRepresentation(const void *Ptr) { + // Because JSON stores integer values as signed 64-bit integers, trying to + // represent them as such makes for very ugly pointer values in the resulting + // output. Instead, we convert the value to hex and treat it as a string. + return "0x" + llvm::utohexstr(reinterpret_cast<uint64_t>(Ptr), true); +} + +llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) { + SplitQualType SQT = QT.split(); + llvm::json::Object Ret{{"qualType", QualType::getAsString(SQT, PrintPolicy)}}; + + if (Desugar && !QT.isNull()) { + SplitQualType DSQT = QT.getSplitDesugaredType(); + if (DSQT != SQT) + Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy); + } + return Ret; +} + +void JSONNodeDumper::writeBareDeclRef(const Decl *D) { + JOS.attribute("id", createPointerRepresentation(D)); + if (!D) + return; + + JOS.attribute("kind", (llvm::Twine(D->getDeclKindName()) + "Decl").str()); + if (const auto *ND = dyn_cast<NamedDecl>(D)) + JOS.attribute("name", ND->getDeclName().getAsString()); + if (const auto *VD = dyn_cast<ValueDecl>(D)) + JOS.attribute("type", createQualType(VD->getType())); +} + +llvm::json::Object JSONNodeDumper::createBareDeclRef(const Decl *D) { + llvm::json::Object Ret{{"id", createPointerRepresentation(D)}}; + if (!D) + return Ret; + + Ret["kind"] = (llvm::Twine(D->getDeclKindName()) + "Decl").str(); + if (const auto *ND = dyn_cast<NamedDecl>(D)) + Ret["name"] = ND->getDeclName().getAsString(); + if (const auto *VD = dyn_cast<ValueDecl>(D)) + Ret["type"] = createQualType(VD->getType()); + return Ret; +} + +llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) { + llvm::json::Array Ret; + if (C->path_empty()) + return Ret; + + for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + const auto *RD = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + llvm::json::Object Val{{"name", RD->getName()}}; + if (Base->isVirtual()) + Val["isVirtual"] = true; + Ret.push_back(std::move(Val)); + } + return Ret; +} + +#define FIELD2(Name, Flag) if (RD->Flag()) Ret[Name] = true +#define FIELD1(Flag) FIELD2(#Flag, Flag) + +static llvm::json::Object +createDefaultConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasDefaultConstructor); + FIELD2("trivial", hasTrivialDefaultConstructor); + FIELD2("nonTrivial", hasNonTrivialDefaultConstructor); + FIELD2("userProvided", hasUserProvidedDefaultConstructor); + FIELD2("isConstexpr", hasConstexprDefaultConstructor); + FIELD2("needsImplicit", needsImplicitDefaultConstructor); + FIELD2("defaultedIsConstexpr", defaultedDefaultConstructorIsConstexpr); + + return Ret; +} + +static llvm::json::Object +createCopyConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("simple", hasSimpleCopyConstructor); + FIELD2("trivial", hasTrivialCopyConstructor); + FIELD2("nonTrivial", hasNonTrivialCopyConstructor); + FIELD2("userDeclared", hasUserDeclaredCopyConstructor); + FIELD2("hasConstParam", hasCopyConstructorWithConstParam); + FIELD2("implicitHasConstParam", implicitCopyConstructorHasConstParam); + FIELD2("needsImplicit", needsImplicitCopyConstructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyConstructor); + if (!RD->needsOverloadResolutionForCopyConstructor()) + FIELD2("defaultedIsDeleted", defaultedCopyConstructorIsDeleted); + + return Ret; +} + +static llvm::json::Object +createMoveConstructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasMoveConstructor); + FIELD2("simple", hasSimpleMoveConstructor); + FIELD2("trivial", hasTrivialMoveConstructor); + FIELD2("nonTrivial", hasNonTrivialMoveConstructor); + FIELD2("userDeclared", hasUserDeclaredMoveConstructor); + FIELD2("needsImplicit", needsImplicitMoveConstructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveConstructor); + if (!RD->needsOverloadResolutionForMoveConstructor()) + FIELD2("defaultedIsDeleted", defaultedMoveConstructorIsDeleted); + + return Ret; +} + +static llvm::json::Object +createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("trivial", hasTrivialCopyAssignment); + FIELD2("nonTrivial", hasNonTrivialCopyAssignment); + FIELD2("hasConstParam", hasCopyAssignmentWithConstParam); + FIELD2("implicitHasConstParam", implicitCopyAssignmentHasConstParam); + FIELD2("userDeclared", hasUserDeclaredCopyAssignment); + FIELD2("needsImplicit", needsImplicitCopyAssignment); + FIELD2("needsOverloadResolution", needsOverloadResolutionForCopyAssignment); + + return Ret; +} + +static llvm::json::Object +createMoveAssignmentDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("exists", hasMoveAssignment); + FIELD2("simple", hasSimpleMoveAssignment); + FIELD2("trivial", hasTrivialMoveAssignment); + FIELD2("nonTrivial", hasNonTrivialMoveAssignment); + FIELD2("userDeclared", hasUserDeclaredMoveAssignment); + FIELD2("needsImplicit", needsImplicitMoveAssignment); + FIELD2("needsOverloadResolution", needsOverloadResolutionForMoveAssignment); + + return Ret; +} + +static llvm::json::Object +createDestructorDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + FIELD2("simple", hasSimpleDestructor); + FIELD2("irrelevant", hasIrrelevantDestructor); + FIELD2("trivial", hasTrivialDestructor); + FIELD2("nonTrivial", hasNonTrivialDestructor); + FIELD2("userDeclared", hasUserDeclaredDestructor); + FIELD2("needsImplicit", needsImplicitDestructor); + FIELD2("needsOverloadResolution", needsOverloadResolutionForDestructor); + if (!RD->needsOverloadResolutionForDestructor()) + FIELD2("defaultedIsDeleted", defaultedDestructorIsDeleted); + + return Ret; +} + +llvm::json::Object +JSONNodeDumper::createCXXRecordDefinitionData(const CXXRecordDecl *RD) { + llvm::json::Object Ret; + + // This data is common to all C++ classes. + FIELD1(isGenericLambda); + FIELD1(isLambda); + FIELD1(isEmpty); + FIELD1(isAggregate); + FIELD1(isStandardLayout); + FIELD1(isTriviallyCopyable); + FIELD1(isPOD); + FIELD1(isTrivial); + FIELD1(isPolymorphic); + FIELD1(isAbstract); + FIELD1(isLiteral); + FIELD1(canPassInRegisters); + FIELD1(hasUserDeclaredConstructor); + FIELD1(hasConstexprNonCopyMoveConstructor); + FIELD1(hasMutableFields); + FIELD1(hasVariantMembers); + FIELD2("canConstDefaultInit", allowConstDefaultInit); + + Ret["defaultCtor"] = createDefaultConstructorDefinitionData(RD); + Ret["copyCtor"] = createCopyConstructorDefinitionData(RD); + Ret["moveCtor"] = createMoveConstructorDefinitionData(RD); + Ret["copyAssign"] = createCopyAssignmentDefinitionData(RD); + Ret["moveAssign"] = createMoveAssignmentDefinitionData(RD); + Ret["dtor"] = createDestructorDefinitionData(RD); + + return Ret; +} + +#undef FIELD1 +#undef FIELD2 + +std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) { + switch (AS) { + case AS_none: return "none"; + case AS_private: return "private"; + case AS_protected: return "protected"; + case AS_public: return "public"; + } + llvm_unreachable("Unknown access specifier"); +} + +llvm::json::Object +JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) { + llvm::json::Object Ret; + + Ret["type"] = createQualType(BS.getType()); + Ret["access"] = createAccessSpecifier(BS.getAccessSpecifier()); + Ret["writtenAccess"] = + createAccessSpecifier(BS.getAccessSpecifierAsWritten()); + if (BS.isVirtual()) + Ret["isVirtual"] = true; + if (BS.isPackExpansion()) + Ret["isPackExpansion"] = true; + + return Ret; +} + +void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { + JOS.attribute("decl", createBareDeclRef(TT->getDecl())); +} + +void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { + FunctionType::ExtInfo E = T->getExtInfo(); + attributeOnlyIfTrue("noreturn", E.getNoReturn()); + attributeOnlyIfTrue("producesResult", E.getProducesResult()); + if (E.getHasRegParm()) + JOS.attribute("regParm", E.getRegParm()); + JOS.attribute("cc", FunctionType::getNameForCallConv(E.getCC())); +} + +void JSONNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) { + FunctionProtoType::ExtProtoInfo E = T->getExtProtoInfo(); + attributeOnlyIfTrue("trailingReturn", E.HasTrailingReturn); + attributeOnlyIfTrue("const", T->isConst()); + attributeOnlyIfTrue("volatile", T->isVolatile()); + attributeOnlyIfTrue("restrict", T->isRestrict()); + attributeOnlyIfTrue("variadic", E.Variadic); + switch (E.RefQualifier) { + case RQ_LValue: JOS.attribute("refQualifier", "&"); break; + case RQ_RValue: JOS.attribute("refQualifier", "&&"); break; + case RQ_None: break; + } + switch (E.ExceptionSpec.Type) { + case EST_DynamicNone: + case EST_Dynamic: { + JOS.attribute("exceptionSpec", "throw"); + llvm::json::Array Types; + for (QualType QT : E.ExceptionSpec.Exceptions) + Types.push_back(createQualType(QT)); + JOS.attribute("exceptionTypes", std::move(Types)); + } break; + case EST_MSAny: + JOS.attribute("exceptionSpec", "throw"); + JOS.attribute("throwsAny", true); + break; + case EST_BasicNoexcept: + JOS.attribute("exceptionSpec", "noexcept"); + break; + case EST_NoexceptTrue: + case EST_NoexceptFalse: + JOS.attribute("exceptionSpec", "noexcept"); + JOS.attribute("conditionEvaluatesTo", + E.ExceptionSpec.Type == EST_NoexceptTrue); + //JOS.attributeWithCall("exceptionSpecExpr", + // [this, E]() { Visit(E.ExceptionSpec.NoexceptExpr); }); + break; + case EST_NoThrow: + JOS.attribute("exceptionSpec", "nothrow"); + break; + // FIXME: I cannot find a way to trigger these cases while dumping the AST. I + // suspect you can only run into them when executing an AST dump from within + // the debugger, which is not a use case we worry about for the JSON dumping + // feature. + case EST_DependentNoexcept: + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + case EST_None: break; + } + VisitFunctionType(T); +} + +void JSONNodeDumper::VisitRValueReferenceType(const ReferenceType *RT) { + attributeOnlyIfTrue("spelledAsLValue", RT->isSpelledAsLValue()); +} + +void JSONNodeDumper::VisitArrayType(const ArrayType *AT) { + switch (AT->getSizeModifier()) { + case ArrayType::Star: + JOS.attribute("sizeModifier", "*"); + break; + case ArrayType::Static: + JOS.attribute("sizeModifier", "static"); + break; + case ArrayType::Normal: + break; + } + + std::string Str = AT->getIndexTypeQualifiers().getAsString(); + if (!Str.empty()) + JOS.attribute("indexTypeQualifiers", Str); +} + +void JSONNodeDumper::VisitConstantArrayType(const ConstantArrayType *CAT) { + // FIXME: this should use ZExt instead of SExt, but JSON doesn't allow a + // narrowing conversion to int64_t so it cannot be expressed. + JOS.attribute("size", CAT->getSize().getSExtValue()); + VisitArrayType(CAT); +} + +void JSONNodeDumper::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *VT) { + JOS.attributeObject( + "attrLoc", [VT, this] { writeSourceLocation(VT->getAttributeLoc()); }); +} + +void JSONNodeDumper::VisitVectorType(const VectorType *VT) { + JOS.attribute("numElements", VT->getNumElements()); + switch (VT->getVectorKind()) { + case VectorType::GenericVector: + break; + case VectorType::AltiVecVector: + JOS.attribute("vectorKind", "altivec"); + break; + case VectorType::AltiVecPixel: + JOS.attribute("vectorKind", "altivec pixel"); + break; + case VectorType::AltiVecBool: + JOS.attribute("vectorKind", "altivec bool"); + break; + case VectorType::NeonVector: + JOS.attribute("vectorKind", "neon"); + break; + case VectorType::NeonPolyVector: + JOS.attribute("vectorKind", "neon poly"); + break; + } +} + +void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) { + JOS.attribute("decl", createBareDeclRef(UUT->getDecl())); +} + +void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) { + switch (UTT->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + JOS.attribute("transformKind", "underlying_type"); + break; + } +} + +void JSONNodeDumper::VisitTagType(const TagType *TT) { + JOS.attribute("decl", createBareDeclRef(TT->getDecl())); +} + +void JSONNodeDumper::VisitTemplateTypeParmType( + const TemplateTypeParmType *TTPT) { + JOS.attribute("depth", TTPT->getDepth()); + JOS.attribute("index", TTPT->getIndex()); + attributeOnlyIfTrue("isPack", TTPT->isParameterPack()); + JOS.attribute("decl", createBareDeclRef(TTPT->getDecl())); +} + +void JSONNodeDumper::VisitAutoType(const AutoType *AT) { + JOS.attribute("undeduced", !AT->isDeduced()); + switch (AT->getKeyword()) { + case AutoTypeKeyword::Auto: + JOS.attribute("typeKeyword", "auto"); + break; + case AutoTypeKeyword::DecltypeAuto: + JOS.attribute("typeKeyword", "decltype(auto)"); + break; + case AutoTypeKeyword::GNUAutoType: + JOS.attribute("typeKeyword", "__auto_type"); + break; + } +} + +void JSONNodeDumper::VisitTemplateSpecializationType( + const TemplateSpecializationType *TST) { + attributeOnlyIfTrue("isAlias", TST->isTypeAlias()); + + std::string Str; + llvm::raw_string_ostream OS(Str); + TST->getTemplateName().print(OS, PrintPolicy); + JOS.attribute("templateName", OS.str()); +} + +void JSONNodeDumper::VisitInjectedClassNameType( + const InjectedClassNameType *ICNT) { + JOS.attribute("decl", createBareDeclRef(ICNT->getDecl())); +} + +void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) { + JOS.attribute("decl", createBareDeclRef(OIT->getDecl())); +} + +void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) { + if (llvm::Optional<unsigned> N = PET->getNumExpansions()) + JOS.attribute("numExpansions", *N); +} + +void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) { + if (const NestedNameSpecifier *NNS = ET->getQualifier()) { + std::string Str; + llvm::raw_string_ostream OS(Str); + NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true); + JOS.attribute("qualifier", OS.str()); + } + if (const TagDecl *TD = ET->getOwnedTagDecl()) + JOS.attribute("ownedTagDecl", createBareDeclRef(TD)); +} + +void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) { + JOS.attribute("macroName", MQT->getMacroIdentifier()->getName()); +} + +void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) { + attributeOnlyIfTrue("isData", MPT->isMemberDataPointer()); + attributeOnlyIfTrue("isFunction", MPT->isMemberFunctionPointer()); +} + +void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) { + if (ND && ND->getDeclName()) + JOS.attribute("name", ND->getNameAsString()); +} + +void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) { + VisitNamedDecl(TD); + JOS.attribute("type", createQualType(TD->getUnderlyingType())); +} + +void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) { + VisitNamedDecl(TAD); + JOS.attribute("type", createQualType(TAD->getUnderlyingType())); +} + +void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) { + VisitNamedDecl(ND); + attributeOnlyIfTrue("isInline", ND->isInline()); + if (!ND->isOriginalNamespace()) + JOS.attribute("originalNamespace", + createBareDeclRef(ND->getOriginalNamespace())); +} + +void JSONNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD) { + JOS.attribute("nominatedNamespace", + createBareDeclRef(UDD->getNominatedNamespace())); +} + +void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) { + VisitNamedDecl(NAD); + JOS.attribute("aliasedNamespace", + createBareDeclRef(NAD->getAliasedNamespace())); +} + +void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) { + std::string Name; + if (const NestedNameSpecifier *NNS = UD->getQualifier()) { + llvm::raw_string_ostream SOS(Name); + NNS->print(SOS, UD->getASTContext().getPrintingPolicy()); + } + Name += UD->getNameAsString(); + JOS.attribute("name", Name); +} + +void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) { + JOS.attribute("target", createBareDeclRef(USD->getTargetDecl())); +} + +void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) { + VisitNamedDecl(VD); + JOS.attribute("type", createQualType(VD->getType())); + + StorageClass SC = VD->getStorageClass(); + if (SC != SC_None) + JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC)); + switch (VD->getTLSKind()) { + case VarDecl::TLS_Dynamic: JOS.attribute("tls", "dynamic"); break; + case VarDecl::TLS_Static: JOS.attribute("tls", "static"); break; + case VarDecl::TLS_None: break; + } + attributeOnlyIfTrue("nrvo", VD->isNRVOVariable()); + attributeOnlyIfTrue("inline", VD->isInline()); + attributeOnlyIfTrue("constexpr", VD->isConstexpr()); + attributeOnlyIfTrue("modulePrivate", VD->isModulePrivate()); + if (VD->hasInit()) { + switch (VD->getInitStyle()) { + case VarDecl::CInit: JOS.attribute("init", "c"); break; + case VarDecl::CallInit: JOS.attribute("init", "call"); break; + case VarDecl::ListInit: JOS.attribute("init", "list"); break; + } + } + attributeOnlyIfTrue("isParameterPack", VD->isParameterPack()); +} + +void JSONNodeDumper::VisitFieldDecl(const FieldDecl *FD) { + VisitNamedDecl(FD); + JOS.attribute("type", createQualType(FD->getType())); + attributeOnlyIfTrue("mutable", FD->isMutable()); + attributeOnlyIfTrue("modulePrivate", FD->isModulePrivate()); + attributeOnlyIfTrue("isBitfield", FD->isBitField()); + attributeOnlyIfTrue("hasInClassInitializer", FD->hasInClassInitializer()); +} + +void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) { + VisitNamedDecl(FD); + JOS.attribute("type", createQualType(FD->getType())); + StorageClass SC = FD->getStorageClass(); + if (SC != SC_None) + JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC)); + attributeOnlyIfTrue("inline", FD->isInlineSpecified()); + attributeOnlyIfTrue("virtual", FD->isVirtualAsWritten()); + attributeOnlyIfTrue("pure", FD->isPure()); + attributeOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten()); + attributeOnlyIfTrue("constexpr", FD->isConstexpr()); + attributeOnlyIfTrue("variadic", FD->isVariadic()); + + if (FD->isDefaulted()) + JOS.attribute("explicitlyDefaulted", + FD->isDeleted() ? "deleted" : "default"); +} + +void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) { + VisitNamedDecl(ED); + if (ED->isFixed()) + JOS.attribute("fixedUnderlyingType", createQualType(ED->getIntegerType())); + if (ED->isScoped()) + JOS.attribute("scopedEnumTag", + ED->isScopedUsingClassTag() ? "class" : "struct"); +} +void JSONNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *ECD) { + VisitNamedDecl(ECD); + JOS.attribute("type", createQualType(ECD->getType())); +} + +void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) { + VisitNamedDecl(RD); + JOS.attribute("tagUsed", RD->getKindName()); + attributeOnlyIfTrue("completeDefinition", RD->isCompleteDefinition()); +} +void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) { + VisitRecordDecl(RD); + + // All other information requires a complete definition. + if (!RD->isCompleteDefinition()) + return; + + JOS.attribute("definitionData", createCXXRecordDefinitionData(RD)); + if (RD->getNumBases()) { + JOS.attributeArray("bases", [this, RD] { + for (const auto &Spec : RD->bases()) + JOS.value(createCXXBaseSpecifier(Spec)); + }); + } +} + +void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + VisitNamedDecl(D); + JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class"); + JOS.attribute("depth", D->getDepth()); + JOS.attribute("index", D->getIndex()); + attributeOnlyIfTrue("isParameterPack", D->isParameterPack()); + + if (D->hasDefaultArgument()) + JOS.attributeObject("defaultArg", [=] { + Visit(D->getDefaultArgument(), SourceRange(), + D->getDefaultArgStorage().getInheritedFrom(), + D->defaultArgumentWasInherited() ? "inherited from" : "previous"); + }); +} + +void JSONNodeDumper::VisitNonTypeTemplateParmDecl( + const NonTypeTemplateParmDecl *D) { + VisitNamedDecl(D); + JOS.attribute("type", createQualType(D->getType())); + JOS.attribute("depth", D->getDepth()); + JOS.attribute("index", D->getIndex()); + attributeOnlyIfTrue("isParameterPack", D->isParameterPack()); + + if (D->hasDefaultArgument()) + JOS.attributeObject("defaultArg", [=] { + Visit(D->getDefaultArgument(), SourceRange(), + D->getDefaultArgStorage().getInheritedFrom(), + D->defaultArgumentWasInherited() ? "inherited from" : "previous"); + }); +} + +void JSONNodeDumper::VisitTemplateTemplateParmDecl( + const TemplateTemplateParmDecl *D) { + VisitNamedDecl(D); + JOS.attribute("depth", D->getDepth()); + JOS.attribute("index", D->getIndex()); + attributeOnlyIfTrue("isParameterPack", D->isParameterPack()); + + if (D->hasDefaultArgument()) + JOS.attributeObject("defaultArg", [=] { + Visit(D->getDefaultArgument().getArgument(), + D->getDefaultArgStorage().getInheritedFrom()->getSourceRange(), + D->getDefaultArgStorage().getInheritedFrom(), + D->defaultArgumentWasInherited() ? "inherited from" : "previous"); + }); +} + +void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) { + StringRef Lang; + switch (LSD->getLanguage()) { + case LinkageSpecDecl::lang_c: Lang = "C"; break; + case LinkageSpecDecl::lang_cxx: Lang = "C++"; break; + } + JOS.attribute("language", Lang); + attributeOnlyIfTrue("hasBraces", LSD->hasBraces()); +} + +void JSONNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *ASD) { + JOS.attribute("access", createAccessSpecifier(ASD->getAccess())); +} + +void JSONNodeDumper::VisitFriendDecl(const FriendDecl *FD) { + if (const TypeSourceInfo *T = FD->getFriendType()) + JOS.attribute("type", createQualType(T->getType())); +} + +void JSONNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { + VisitNamedDecl(D); + JOS.attribute("type", createQualType(D->getType())); + attributeOnlyIfTrue("synthesized", D->getSynthesize()); + switch (D->getAccessControl()) { + case ObjCIvarDecl::None: JOS.attribute("access", "none"); break; + case ObjCIvarDecl::Private: JOS.attribute("access", "private"); break; + case ObjCIvarDecl::Protected: JOS.attribute("access", "protected"); break; + case ObjCIvarDecl::Public: JOS.attribute("access", "public"); break; + case ObjCIvarDecl::Package: JOS.attribute("access", "package"); break; + } +} + +void JSONNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { + VisitNamedDecl(D); + JOS.attribute("returnType", createQualType(D->getReturnType())); + JOS.attribute("instance", D->isInstanceMethod()); + attributeOnlyIfTrue("variadic", D->isVariadic()); +} + +void JSONNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { + VisitNamedDecl(D); + JOS.attribute("type", createQualType(D->getUnderlyingType())); + attributeOnlyIfTrue("bounded", D->hasExplicitBound()); + switch (D->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + case ObjCTypeParamVariance::Covariant: + JOS.attribute("variance", "covariant"); + break; + case ObjCTypeParamVariance::Contravariant: + JOS.attribute("variance", "contravariant"); + break; + } +} + +void JSONNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + VisitNamedDecl(D); + JOS.attribute("interface", createBareDeclRef(D->getClassInterface())); + JOS.attribute("implementation", createBareDeclRef(D->getImplementation())); + + llvm::json::Array Protocols; + for (const auto* P : D->protocols()) + Protocols.push_back(createBareDeclRef(P)); + if (!Protocols.empty()) + JOS.attribute("protocols", std::move(Protocols)); +} + +void JSONNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + VisitNamedDecl(D); + JOS.attribute("interface", createBareDeclRef(D->getClassInterface())); + JOS.attribute("categoryDecl", createBareDeclRef(D->getCategoryDecl())); +} + +void JSONNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + VisitNamedDecl(D); + + llvm::json::Array Protocols; + for (const auto *P : D->protocols()) + Protocols.push_back(createBareDeclRef(P)); + if (!Protocols.empty()) + JOS.attribute("protocols", std::move(Protocols)); +} + +void JSONNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + VisitNamedDecl(D); + JOS.attribute("super", createBareDeclRef(D->getSuperClass())); + JOS.attribute("implementation", createBareDeclRef(D->getImplementation())); + + llvm::json::Array Protocols; + for (const auto* P : D->protocols()) + Protocols.push_back(createBareDeclRef(P)); + if (!Protocols.empty()) + JOS.attribute("protocols", std::move(Protocols)); +} + +void JSONNodeDumper::VisitObjCImplementationDecl( + const ObjCImplementationDecl *D) { + VisitNamedDecl(D); + JOS.attribute("super", createBareDeclRef(D->getSuperClass())); + JOS.attribute("interface", createBareDeclRef(D->getClassInterface())); +} + +void JSONNodeDumper::VisitObjCCompatibleAliasDecl( + const ObjCCompatibleAliasDecl *D) { + VisitNamedDecl(D); + JOS.attribute("interface", createBareDeclRef(D->getClassInterface())); +} + +void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + VisitNamedDecl(D); + JOS.attribute("type", createQualType(D->getType())); + + switch (D->getPropertyImplementation()) { + case ObjCPropertyDecl::None: break; + case ObjCPropertyDecl::Required: JOS.attribute("control", "required"); break; + case ObjCPropertyDecl::Optional: JOS.attribute("control", "optional"); break; + } + + ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); + if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { + if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) + JOS.attribute("getter", createBareDeclRef(D->getGetterMethodDecl())); + if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) + JOS.attribute("setter", createBareDeclRef(D->getSetterMethodDecl())); + attributeOnlyIfTrue("readonly", Attrs & ObjCPropertyDecl::OBJC_PR_readonly); + attributeOnlyIfTrue("assign", Attrs & ObjCPropertyDecl::OBJC_PR_assign); + attributeOnlyIfTrue("readwrite", + Attrs & ObjCPropertyDecl::OBJC_PR_readwrite); + attributeOnlyIfTrue("retain", Attrs & ObjCPropertyDecl::OBJC_PR_retain); + attributeOnlyIfTrue("copy", Attrs & ObjCPropertyDecl::OBJC_PR_copy); + attributeOnlyIfTrue("nonatomic", + Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic); + attributeOnlyIfTrue("atomic", Attrs & ObjCPropertyDecl::OBJC_PR_atomic); + attributeOnlyIfTrue("weak", Attrs & ObjCPropertyDecl::OBJC_PR_weak); + attributeOnlyIfTrue("strong", Attrs & ObjCPropertyDecl::OBJC_PR_strong); + attributeOnlyIfTrue("unsafe_unretained", + Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class); + attributeOnlyIfTrue("nullability", + Attrs & ObjCPropertyDecl::OBJC_PR_nullability); + attributeOnlyIfTrue("null_resettable", + Attrs & ObjCPropertyDecl::OBJC_PR_null_resettable); + } +} + +void JSONNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + VisitNamedDecl(D->getPropertyDecl()); + JOS.attribute("implKind", D->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize + ? "synthesize" + : "dynamic"); + JOS.attribute("propertyDecl", createBareDeclRef(D->getPropertyDecl())); + JOS.attribute("ivarDecl", createBareDeclRef(D->getPropertyIvarDecl())); +} + +void JSONNodeDumper::VisitBlockDecl(const BlockDecl *D) { + attributeOnlyIfTrue("variadic", D->isVariadic()); + attributeOnlyIfTrue("capturesThis", D->capturesCXXThis()); +} + +void JSONNodeDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE) { + JOS.attribute("encodedType", createQualType(OEE->getEncodedType())); +} + +void JSONNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *OME) { + std::string Str; + llvm::raw_string_ostream OS(Str); + + OME->getSelector().print(OS); + JOS.attribute("selector", OS.str()); + + switch (OME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + JOS.attribute("receiverKind", "instance"); + break; + case ObjCMessageExpr::Class: + JOS.attribute("receiverKind", "class"); + JOS.attribute("classType", createQualType(OME->getClassReceiver())); + break; + case ObjCMessageExpr::SuperInstance: + JOS.attribute("receiverKind", "super (instance)"); + JOS.attribute("superType", createQualType(OME->getSuperType())); + break; + case ObjCMessageExpr::SuperClass: + JOS.attribute("receiverKind", "super (class)"); + JOS.attribute("superType", createQualType(OME->getSuperType())); + break; + } + + QualType CallReturnTy = OME->getCallReturnType(Ctx); + if (OME->getType() != CallReturnTy) + JOS.attribute("callReturnType", createQualType(CallReturnTy)); +} + +void JSONNodeDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *OBE) { + if (const ObjCMethodDecl *MD = OBE->getBoxingMethod()) { + std::string Str; + llvm::raw_string_ostream OS(Str); + + MD->getSelector().print(OS); + JOS.attribute("selector", OS.str()); + } +} + +void JSONNodeDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *OSE) { + std::string Str; + llvm::raw_string_ostream OS(Str); + + OSE->getSelector().print(OS); + JOS.attribute("selector", OS.str()); +} + +void JSONNodeDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *OPE) { + JOS.attribute("protocol", createBareDeclRef(OPE->getProtocol())); +} + +void JSONNodeDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *OPRE) { + if (OPRE->isImplicitProperty()) { + JOS.attribute("propertyKind", "implicit"); + if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertyGetter()) + JOS.attribute("getter", createBareDeclRef(MD)); + if (const ObjCMethodDecl *MD = OPRE->getImplicitPropertySetter()) + JOS.attribute("setter", createBareDeclRef(MD)); + } else { + JOS.attribute("propertyKind", "explicit"); + JOS.attribute("property", createBareDeclRef(OPRE->getExplicitProperty())); + } + + attributeOnlyIfTrue("isSuperReceiver", OPRE->isSuperReceiver()); + attributeOnlyIfTrue("isMessagingGetter", OPRE->isMessagingGetter()); + attributeOnlyIfTrue("isMessagingSetter", OPRE->isMessagingSetter()); +} + +void JSONNodeDumper::VisitObjCSubscriptRefExpr( + const ObjCSubscriptRefExpr *OSRE) { + JOS.attribute("subscriptKind", + OSRE->isArraySubscriptRefExpr() ? "array" : "dictionary"); + + if (const ObjCMethodDecl *MD = OSRE->getAtIndexMethodDecl()) + JOS.attribute("getter", createBareDeclRef(MD)); + if (const ObjCMethodDecl *MD = OSRE->setAtIndexMethodDecl()) + JOS.attribute("setter", createBareDeclRef(MD)); +} + +void JSONNodeDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE) { + JOS.attribute("decl", createBareDeclRef(OIRE->getDecl())); + attributeOnlyIfTrue("isFreeIvar", OIRE->isFreeIvar()); + JOS.attribute("isArrow", OIRE->isArrow()); +} + +void JSONNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *OBLE) { + JOS.attribute("value", OBLE->getValue() ? "__objc_yes" : "__objc_no"); +} + +void JSONNodeDumper::VisitDeclRefExpr(const DeclRefExpr *DRE) { + JOS.attribute("referencedDecl", createBareDeclRef(DRE->getDecl())); + if (DRE->getDecl() != DRE->getFoundDecl()) + JOS.attribute("foundReferencedDecl", + createBareDeclRef(DRE->getFoundDecl())); + switch (DRE->isNonOdrUse()) { + case NOUR_None: break; + case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break; + case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break; + case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break; + } +} + +void JSONNodeDumper::VisitPredefinedExpr(const PredefinedExpr *PE) { + JOS.attribute("name", PredefinedExpr::getIdentKindName(PE->getIdentKind())); +} + +void JSONNodeDumper::VisitUnaryOperator(const UnaryOperator *UO) { + JOS.attribute("isPostfix", UO->isPostfix()); + JOS.attribute("opcode", UnaryOperator::getOpcodeStr(UO->getOpcode())); + if (!UO->canOverflow()) + JOS.attribute("canOverflow", false); +} + +void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) { + JOS.attribute("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode())); +} + +void JSONNodeDumper::VisitCompoundAssignOperator( + const CompoundAssignOperator *CAO) { + VisitBinaryOperator(CAO); + JOS.attribute("computeLHSType", createQualType(CAO->getComputationLHSType())); + JOS.attribute("computeResultType", + createQualType(CAO->getComputationResultType())); +} + +void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) { + // Note, we always write this Boolean field because the information it conveys + // is critical to understanding the AST node. + ValueDecl *VD = ME->getMemberDecl(); + JOS.attribute("name", VD && VD->getDeclName() ? VD->getNameAsString() : ""); + JOS.attribute("isArrow", ME->isArrow()); + JOS.attribute("referencedMemberDecl", createPointerRepresentation(VD)); + switch (ME->isNonOdrUse()) { + case NOUR_None: break; + case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break; + case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break; + case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break; + } +} + +void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) { + attributeOnlyIfTrue("isGlobal", NE->isGlobalNew()); + attributeOnlyIfTrue("isArray", NE->isArray()); + attributeOnlyIfTrue("isPlacement", NE->getNumPlacementArgs() != 0); + switch (NE->getInitializationStyle()) { + case CXXNewExpr::NoInit: break; + case CXXNewExpr::CallInit: JOS.attribute("initStyle", "call"); break; + case CXXNewExpr::ListInit: JOS.attribute("initStyle", "list"); break; + } + if (const FunctionDecl *FD = NE->getOperatorNew()) + JOS.attribute("operatorNewDecl", createBareDeclRef(FD)); + if (const FunctionDecl *FD = NE->getOperatorDelete()) + JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD)); +} +void JSONNodeDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) { + attributeOnlyIfTrue("isGlobal", DE->isGlobalDelete()); + attributeOnlyIfTrue("isArray", DE->isArrayForm()); + attributeOnlyIfTrue("isArrayAsWritten", DE->isArrayFormAsWritten()); + if (const FunctionDecl *FD = DE->getOperatorDelete()) + JOS.attribute("operatorDeleteDecl", createBareDeclRef(FD)); +} + +void JSONNodeDumper::VisitCXXThisExpr(const CXXThisExpr *TE) { + attributeOnlyIfTrue("implicit", TE->isImplicit()); +} + +void JSONNodeDumper::VisitCastExpr(const CastExpr *CE) { + JOS.attribute("castKind", CE->getCastKindName()); + llvm::json::Array Path = createCastPath(CE); + if (!Path.empty()) + JOS.attribute("path", std::move(Path)); + // FIXME: This may not be useful information as it can be obtusely gleaned + // from the inner[] array. + if (const NamedDecl *ND = CE->getConversionFunction()) + JOS.attribute("conversionFunc", createBareDeclRef(ND)); +} + +void JSONNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) { + VisitCastExpr(ICE); + attributeOnlyIfTrue("isPartOfExplicitCast", ICE->isPartOfExplicitCast()); +} + +void JSONNodeDumper::VisitCallExpr(const CallExpr *CE) { + attributeOnlyIfTrue("adl", CE->usesADL()); +} + +void JSONNodeDumper::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *TTE) { + switch (TTE->getKind()) { + case UETT_SizeOf: JOS.attribute("name", "sizeof"); break; + case UETT_AlignOf: JOS.attribute("name", "alignof"); break; + case UETT_VecStep: JOS.attribute("name", "vec_step"); break; + case UETT_PreferredAlignOf: JOS.attribute("name", "__alignof"); break; + case UETT_OpenMPRequiredSimdAlign: + JOS.attribute("name", "__builtin_omp_required_simd_align"); break; + } + if (TTE->isArgumentType()) + JOS.attribute("argType", createQualType(TTE->getArgumentType())); +} + +void JSONNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE) { + VisitNamedDecl(SOPE->getPack()); +} + +void JSONNodeDumper::VisitUnresolvedLookupExpr( + const UnresolvedLookupExpr *ULE) { + JOS.attribute("usesADL", ULE->requiresADL()); + JOS.attribute("name", ULE->getName().getAsString()); + + JOS.attributeArray("lookups", [this, ULE] { + for (const NamedDecl *D : ULE->decls()) + JOS.value(createBareDeclRef(D)); + }); +} + +void JSONNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *ALE) { + JOS.attribute("name", ALE->getLabel()->getName()); + JOS.attribute("labelDeclId", createPointerRepresentation(ALE->getLabel())); +} + +void JSONNodeDumper::VisitCXXTypeidExpr(const CXXTypeidExpr *CTE) { + if (CTE->isTypeOperand()) { + QualType Adjusted = CTE->getTypeOperand(Ctx); + QualType Unadjusted = CTE->getTypeOperandSourceInfo()->getType(); + JOS.attribute("typeArg", createQualType(Unadjusted)); + if (Adjusted != Unadjusted) + JOS.attribute("adjustedTypeArg", createQualType(Adjusted)); + } +} + +void JSONNodeDumper::VisitConstantExpr(const ConstantExpr *CE) { + if (CE->getResultAPValueKind() != APValue::None) { + std::string Str; + llvm::raw_string_ostream OS(Str); + CE->getAPValueResult().printPretty(OS, Ctx, CE->getType()); + JOS.attribute("value", OS.str()); + } +} + +void JSONNodeDumper::VisitInitListExpr(const InitListExpr *ILE) { + if (const FieldDecl *FD = ILE->getInitializedFieldInUnion()) + JOS.attribute("field", createBareDeclRef(FD)); +} + +void JSONNodeDumper::VisitGenericSelectionExpr( + const GenericSelectionExpr *GSE) { + attributeOnlyIfTrue("resultDependent", GSE->isResultDependent()); +} + +void JSONNodeDumper::VisitCXXUnresolvedConstructExpr( + const CXXUnresolvedConstructExpr *UCE) { + if (UCE->getType() != UCE->getTypeAsWritten()) + JOS.attribute("typeAsWritten", createQualType(UCE->getTypeAsWritten())); + attributeOnlyIfTrue("list", UCE->isListInitialization()); +} + +void JSONNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *CE) { + CXXConstructorDecl *Ctor = CE->getConstructor(); + JOS.attribute("ctorType", createQualType(Ctor->getType())); + attributeOnlyIfTrue("elidable", CE->isElidable()); + attributeOnlyIfTrue("list", CE->isListInitialization()); + attributeOnlyIfTrue("initializer_list", CE->isStdInitListInitialization()); + attributeOnlyIfTrue("zeroing", CE->requiresZeroInitialization()); + attributeOnlyIfTrue("hadMultipleCandidates", CE->hadMultipleCandidates()); + + switch (CE->getConstructionKind()) { + case CXXConstructExpr::CK_Complete: + JOS.attribute("constructionKind", "complete"); + break; + case CXXConstructExpr::CK_Delegating: + JOS.attribute("constructionKind", "delegating"); + break; + case CXXConstructExpr::CK_NonVirtualBase: + JOS.attribute("constructionKind", "non-virtual base"); + break; + case CXXConstructExpr::CK_VirtualBase: + JOS.attribute("constructionKind", "virtual base"); + break; + } +} + +void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) { + attributeOnlyIfTrue("cleanupsHaveSideEffects", + EWC->cleanupsHaveSideEffects()); + if (EWC->getNumObjects()) { + JOS.attributeArray("cleanups", [this, EWC] { + for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects()) + JOS.value(createBareDeclRef(CO)); + }); + } +} + +void JSONNodeDumper::VisitCXXBindTemporaryExpr( + const CXXBindTemporaryExpr *BTE) { + const CXXTemporary *Temp = BTE->getTemporary(); + JOS.attribute("temp", createPointerRepresentation(Temp)); + if (const CXXDestructorDecl *Dtor = Temp->getDestructor()) + JOS.attribute("dtor", createBareDeclRef(Dtor)); +} + +void JSONNodeDumper::VisitMaterializeTemporaryExpr( + const MaterializeTemporaryExpr *MTE) { + if (const ValueDecl *VD = MTE->getExtendingDecl()) + JOS.attribute("extendingDecl", createBareDeclRef(VD)); + + switch (MTE->getStorageDuration()) { + case SD_Automatic: + JOS.attribute("storageDuration", "automatic"); + break; + case SD_Dynamic: + JOS.attribute("storageDuration", "dynamic"); + break; + case SD_FullExpression: + JOS.attribute("storageDuration", "full expression"); + break; + case SD_Static: + JOS.attribute("storageDuration", "static"); + break; + case SD_Thread: + JOS.attribute("storageDuration", "thread"); + break; + } + + attributeOnlyIfTrue("boundToLValueRef", MTE->isBoundToLvalueReference()); +} + +void JSONNodeDumper::VisitCXXDependentScopeMemberExpr( + const CXXDependentScopeMemberExpr *DSME) { + JOS.attribute("isArrow", DSME->isArrow()); + JOS.attribute("member", DSME->getMember().getAsString()); + attributeOnlyIfTrue("hasTemplateKeyword", DSME->hasTemplateKeyword()); + attributeOnlyIfTrue("hasExplicitTemplateArgs", + DSME->hasExplicitTemplateArgs()); + + if (DSME->getNumTemplateArgs()) { + JOS.attributeArray("explicitTemplateArgs", [DSME, this] { + for (const TemplateArgumentLoc &TAL : DSME->template_arguments()) + JOS.object( + [&TAL, this] { Visit(TAL.getArgument(), TAL.getSourceRange()); }); + }); + } +} + +void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) { + JOS.attribute("value", + IL->getValue().toString( + /*Radix=*/10, IL->getType()->isSignedIntegerType())); +} +void JSONNodeDumper::VisitCharacterLiteral(const CharacterLiteral *CL) { + // FIXME: This should probably print the character literal as a string, + // rather than as a numerical value. It would be nice if the behavior matched + // what we do to print a string literal; right now, it is impossible to tell + // the difference between 'a' and L'a' in C from the JSON output. + JOS.attribute("value", CL->getValue()); +} +void JSONNodeDumper::VisitFixedPointLiteral(const FixedPointLiteral *FPL) { + JOS.attribute("value", FPL->getValueAsString(/*Radix=*/10)); +} +void JSONNodeDumper::VisitFloatingLiteral(const FloatingLiteral *FL) { + llvm::SmallVector<char, 16> Buffer; + FL->getValue().toString(Buffer); + JOS.attribute("value", Buffer); +} +void JSONNodeDumper::VisitStringLiteral(const StringLiteral *SL) { + std::string Buffer; + llvm::raw_string_ostream SS(Buffer); + SL->outputString(SS); + JOS.attribute("value", SS.str()); +} +void JSONNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *BLE) { + JOS.attribute("value", BLE->getValue()); +} + +void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) { + attributeOnlyIfTrue("hasInit", IS->hasInitStorage()); + attributeOnlyIfTrue("hasVar", IS->hasVarStorage()); + attributeOnlyIfTrue("hasElse", IS->hasElseStorage()); + attributeOnlyIfTrue("isConstexpr", IS->isConstexpr()); +} + +void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) { + attributeOnlyIfTrue("hasInit", SS->hasInitStorage()); + attributeOnlyIfTrue("hasVar", SS->hasVarStorage()); +} +void JSONNodeDumper::VisitCaseStmt(const CaseStmt *CS) { + attributeOnlyIfTrue("isGNURange", CS->caseStmtIsGNURange()); +} + +void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) { + JOS.attribute("name", LS->getName()); + JOS.attribute("declId", createPointerRepresentation(LS->getDecl())); +} +void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) { + JOS.attribute("targetLabelDeclId", + createPointerRepresentation(GS->getLabel())); +} + +void JSONNodeDumper::VisitWhileStmt(const WhileStmt *WS) { + attributeOnlyIfTrue("hasVar", WS->hasVarStorage()); +} + +void JSONNodeDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt* OACS) { + // FIXME: it would be nice for the ASTNodeTraverser would handle the catch + // parameter the same way for C++ and ObjC rather. In this case, C++ gets a + // null child node and ObjC gets no child node. + attributeOnlyIfTrue("isCatchAll", OACS->getCatchParamDecl() == nullptr); +} + +void JSONNodeDumper::VisitNullTemplateArgument(const TemplateArgument &TA) { + JOS.attribute("isNull", true); +} +void JSONNodeDumper::VisitTypeTemplateArgument(const TemplateArgument &TA) { + JOS.attribute("type", createQualType(TA.getAsType())); +} +void JSONNodeDumper::VisitDeclarationTemplateArgument( + const TemplateArgument &TA) { + JOS.attribute("decl", createBareDeclRef(TA.getAsDecl())); +} +void JSONNodeDumper::VisitNullPtrTemplateArgument(const TemplateArgument &TA) { + JOS.attribute("isNullptr", true); +} +void JSONNodeDumper::VisitIntegralTemplateArgument(const TemplateArgument &TA) { + JOS.attribute("value", TA.getAsIntegral().getSExtValue()); +} +void JSONNodeDumper::VisitTemplateTemplateArgument(const TemplateArgument &TA) { + // FIXME: cannot just call dump() on the argument, as that doesn't specify + // the output format. +} +void JSONNodeDumper::VisitTemplateExpansionTemplateArgument( + const TemplateArgument &TA) { + // FIXME: cannot just call dump() on the argument, as that doesn't specify + // the output format. +} +void JSONNodeDumper::VisitExpressionTemplateArgument( + const TemplateArgument &TA) { + JOS.attribute("isExpr", true); +} +void JSONNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) { + JOS.attribute("isPack", true); +} + +StringRef JSONNodeDumper::getCommentCommandName(unsigned CommandID) const { + if (Traits) + return Traits->getCommandInfo(CommandID)->Name; + if (const comments::CommandInfo *Info = + comments::CommandTraits::getBuiltinCommandInfo(CommandID)) + return Info->Name; + return "<invalid>"; +} + +void JSONNodeDumper::visitTextComment(const comments::TextComment *C, + const comments::FullComment *) { + JOS.attribute("text", C->getText()); +} + +void JSONNodeDumper::visitInlineCommandComment( + const comments::InlineCommandComment *C, const comments::FullComment *) { + JOS.attribute("name", getCommentCommandName(C->getCommandID())); + + switch (C->getRenderKind()) { + case comments::InlineCommandComment::RenderNormal: + JOS.attribute("renderKind", "normal"); + break; + case comments::InlineCommandComment::RenderBold: + JOS.attribute("renderKind", "bold"); + break; + case comments::InlineCommandComment::RenderEmphasized: + JOS.attribute("renderKind", "emphasized"); + break; + case comments::InlineCommandComment::RenderMonospaced: + JOS.attribute("renderKind", "monospaced"); + break; + } + + llvm::json::Array Args; + for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I) + Args.push_back(C->getArgText(I)); + + if (!Args.empty()) + JOS.attribute("args", std::move(Args)); +} + +void JSONNodeDumper::visitHTMLStartTagComment( + const comments::HTMLStartTagComment *C, const comments::FullComment *) { + JOS.attribute("name", C->getTagName()); + attributeOnlyIfTrue("selfClosing", C->isSelfClosing()); + attributeOnlyIfTrue("malformed", C->isMalformed()); + + llvm::json::Array Attrs; + for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) + Attrs.push_back( + {{"name", C->getAttr(I).Name}, {"value", C->getAttr(I).Value}}); + + if (!Attrs.empty()) + JOS.attribute("attrs", std::move(Attrs)); +} + +void JSONNodeDumper::visitHTMLEndTagComment( + const comments::HTMLEndTagComment *C, const comments::FullComment *) { + JOS.attribute("name", C->getTagName()); +} + +void JSONNodeDumper::visitBlockCommandComment( + const comments::BlockCommandComment *C, const comments::FullComment *) { + JOS.attribute("name", getCommentCommandName(C->getCommandID())); + + llvm::json::Array Args; + for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I) + Args.push_back(C->getArgText(I)); + + if (!Args.empty()) + JOS.attribute("args", std::move(Args)); +} + +void JSONNodeDumper::visitParamCommandComment( + const comments::ParamCommandComment *C, const comments::FullComment *FC) { + switch (C->getDirection()) { + case comments::ParamCommandComment::In: + JOS.attribute("direction", "in"); + break; + case comments::ParamCommandComment::Out: + JOS.attribute("direction", "out"); + break; + case comments::ParamCommandComment::InOut: + JOS.attribute("direction", "in,out"); + break; + } + attributeOnlyIfTrue("explicit", C->isDirectionExplicit()); + + if (C->hasParamName()) + JOS.attribute("param", C->isParamIndexValid() ? C->getParamName(FC) + : C->getParamNameAsWritten()); + + if (C->isParamIndexValid() && !C->isVarArgParam()) + JOS.attribute("paramIdx", C->getParamIndex()); +} + +void JSONNodeDumper::visitTParamCommandComment( + const comments::TParamCommandComment *C, const comments::FullComment *FC) { + if (C->hasParamName()) + JOS.attribute("param", C->isPositionValid() ? C->getParamName(FC) + : C->getParamNameAsWritten()); + if (C->isPositionValid()) { + llvm::json::Array Positions; + for (unsigned I = 0, E = C->getDepth(); I < E; ++I) + Positions.push_back(C->getIndex(I)); + + if (!Positions.empty()) + JOS.attribute("positions", std::move(Positions)); + } +} + +void JSONNodeDumper::visitVerbatimBlockComment( + const comments::VerbatimBlockComment *C, const comments::FullComment *) { + JOS.attribute("name", getCommentCommandName(C->getCommandID())); + JOS.attribute("closeName", C->getCloseName()); +} + +void JSONNodeDumper::visitVerbatimBlockLineComment( + const comments::VerbatimBlockLineComment *C, + const comments::FullComment *) { + JOS.attribute("text", C->getText()); +} + +void JSONNodeDumper::visitVerbatimLineComment( + const comments::VerbatimLineComment *C, const comments::FullComment *) { + JOS.attribute("text", C->getText()); +} diff --git a/lib/AST/Linkage.h b/lib/AST/Linkage.h index 8ad748bcc4a26..4e913540de86f 100644 --- a/lib/AST/Linkage.h +++ b/lib/AST/Linkage.h @@ -1,9 +1,8 @@ //===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index bb29bffc1b8fb..625282368a4d1 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -1,9 +1,8 @@ //===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -18,10 +17,13 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" +#include "clang/AST/VTableBuilder.h" #include "clang/Basic/ABI.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -281,3 +283,205 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, mangleObjCMethodNameWithoutSize(MD, OS); Out << OS.str().size() << OS.str(); } + +class ASTNameGenerator::Implementation { + std::unique_ptr<MangleContext> MC; + llvm::DataLayout DL; + +public: + explicit Implementation(ASTContext &Ctx) + : MC(Ctx.createMangleContext()), DL(Ctx.getTargetInfo().getDataLayout()) { + } + + bool writeName(const Decl *D, raw_ostream &OS) { + // First apply frontend mangling. + SmallString<128> FrontendBuf; + llvm::raw_svector_ostream FrontendBufOS(FrontendBuf); + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDependentContext()) + return true; + if (writeFuncOrVarName(FD, FrontendBufOS)) + return true; + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + if (writeFuncOrVarName(VD, FrontendBufOS)) + return true; + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + MC->mangleObjCMethodNameWithoutSize(MD, OS); + return false; + } else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + writeObjCClassName(ID, FrontendBufOS); + } else { + return true; + } + + // Now apply backend mangling. + llvm::Mangler::getNameWithPrefix(OS, FrontendBufOS.str(), DL); + return false; + } + + std::string getName(const Decl *D) { + std::string Name; + { + llvm::raw_string_ostream OS(Name); + writeName(D, OS); + } + return Name; + } + + enum ObjCKind { + ObjCClass, + ObjCMetaclass, + }; + + static StringRef getClassSymbolPrefix(ObjCKind Kind, + const ASTContext &Context) { + if (Context.getLangOpts().ObjCRuntime.isGNUFamily()) + return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_"; + return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_"; + } + + std::vector<std::string> getAllManglings(const ObjCContainerDecl *OCD) { + StringRef ClassName; + if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + else if (const auto *OID = dyn_cast<ObjCImplementationDecl>(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + + if (ClassName.empty()) + return {}; + + auto Mangle = [&](ObjCKind Kind, StringRef ClassName) -> std::string { + SmallString<40> Mangled; + auto Prefix = getClassSymbolPrefix(Kind, OCD->getASTContext()); + llvm::Mangler::getNameWithPrefix(Mangled, Prefix + ClassName, DL); + return Mangled.str(); + }; + + return { + Mangle(ObjCClass, ClassName), + Mangle(ObjCMetaclass, ClassName), + }; + } + + std::vector<std::string> getAllManglings(const Decl *D) { + if (const auto *OCD = dyn_cast<ObjCContainerDecl>(D)) + return getAllManglings(OCD); + + if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D))) + return {}; + + const NamedDecl *ND = cast<NamedDecl>(D); + + ASTContext &Ctx = ND->getASTContext(); + std::unique_ptr<MangleContext> M(Ctx.createMangleContext()); + + std::vector<std::string> Manglings; + + auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) { + auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCXXMethod=*/true); + auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv(); + return CC == DefaultCC; + }; + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(CD, Ctor_Base)); + + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) + if (!CD->getParent()->isAbstract()) + Manglings.emplace_back(getMangledStructor(CD, Ctor_Complete)); + + if (Ctx.getTargetInfo().getCXXABI().isMicrosoft()) + if (CD->hasAttr<DLLExportAttr>() && CD->isDefaultConstructor()) + if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0)) + Manglings.emplace_back(getMangledStructor(CD, Ctor_DefaultClosure)); + } else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Base)); + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Complete)); + if (DD->isVirtual()) + Manglings.emplace_back(getMangledStructor(DD, Dtor_Deleting)); + } + } else if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(ND)) { + Manglings.emplace_back(getName(ND)); + if (MD->isVirtual()) + if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) + for (const auto &T : *TIV) + Manglings.emplace_back(getMangledThunk(MD, T)); + } + + return Manglings; + } + +private: + bool writeFuncOrVarName(const NamedDecl *D, raw_ostream &OS) { + if (MC->shouldMangleDeclName(D)) { + if (const auto *CtorD = dyn_cast<CXXConstructorDecl>(D)) + MC->mangleCXXCtor(CtorD, Ctor_Complete, OS); + else if (const auto *DtorD = dyn_cast<CXXDestructorDecl>(D)) + MC->mangleCXXDtor(DtorD, Dtor_Complete, OS); + else + MC->mangleName(D, OS); + return false; + } else { + IdentifierInfo *II = D->getIdentifier(); + if (!II) + return true; + OS << II->getName(); + return false; + } + } + + void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) { + OS << getClassSymbolPrefix(ObjCClass, D->getASTContext()); + OS << D->getObjCRuntimeNameAsString(); + } + + std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) + MC->mangleCXXCtor(CD, static_cast<CXXCtorType>(StructorType), FOS); + else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) + MC->mangleCXXDtor(DD, static_cast<CXXDtorType>(StructorType), FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } + + std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + MC->mangleThunk(MD, T, FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } +}; + +ASTNameGenerator::ASTNameGenerator(ASTContext &Ctx) + : Impl(llvm::make_unique<Implementation>(Ctx)) {} + +ASTNameGenerator::~ASTNameGenerator() {} + +bool ASTNameGenerator::writeName(const Decl *D, raw_ostream &OS) { + return Impl->writeName(D, OS); +} + +std::string ASTNameGenerator::getName(const Decl *D) { + return Impl->getName(D); +} + +std::vector<std::string> ASTNameGenerator::getAllManglings(const Decl *D) { + return Impl->getAllManglings(D); +} diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 3b417c1352850..4dc4156df9ca4 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -1,9 +1,8 @@ //===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 92e9679e49aa3..5e9358e24fc9d 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1,9 +1,8 @@ //===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -32,6 +31,7 @@ #include "llvm/Support/xxhash.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/StringSaver.h" using namespace clang; @@ -97,7 +97,8 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { } const DeclContext *DC = D->getDeclContext(); - if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) { + if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC) || + isa<OMPDeclareMapperDecl>(DC)) { return getEffectiveDeclContext(cast<Decl>(DC)); } @@ -265,9 +266,15 @@ class MicrosoftCXXNameMangler { BackRefVec NameBackReferences; typedef llvm::DenseMap<const void *, unsigned> ArgBackRefMap; - ArgBackRefMap TypeBackReferences; + ArgBackRefMap FunArgBackReferences; + ArgBackRefMap TemplateArgBackReferences; + + typedef llvm::DenseMap<const void *, StringRef> TemplateArgStringMap; + TemplateArgStringMap TemplateArgStrings; + llvm::StringSaver TemplateArgStringStorage; + llvm::BumpPtrAllocator TemplateArgStringStorageAlloc; - typedef std::set<int> PassObjectSizeArgsSet; + typedef std::set<std::pair<int, bool>> PassObjectSizeArgsSet; PassObjectSizeArgsSet PassObjectSizeArgs; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -281,18 +288,21 @@ public: MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(nullptr), StructorType(-1), + TemplateArgStringStorage(TemplateArgStringStorageAlloc), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + TemplateArgStringStorage(TemplateArgStringStorageAlloc), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + TemplateArgStringStorage(TemplateArgStringStorageAlloc), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == 64) {} @@ -343,7 +353,7 @@ private: const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); - void mangleArgumentType(QualType T, SourceRange Range); + void mangleFunctionArgumentType(QualType T, SourceRange Range); void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA); bool isArtificialTagType(QualType T) const; @@ -793,7 +803,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // the X<Y> part is aliased. However, if you need to mangle // void foo(A::X<A::Y>, A::X<B::Y>), // the A::X<> part is not aliased. - // That said, from the mangler's perspective we have a structure like this: + // That is, from the mangler's perspective we have a structure like this: // namespace[s] -> type[ -> template-parameters] // but from the Clang perspective we have // type [ -> template-parameters] @@ -803,12 +813,40 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // the mangled type name as a key to check the mangling of different types // for aliasing. - llvm::SmallString<64> TemplateMangling; - llvm::raw_svector_ostream Stream(TemplateMangling); - MicrosoftCXXNameMangler Extra(Context, Stream); - Extra.mangleTemplateInstantiationName(TD, *TemplateArgs); - - mangleSourceName(TemplateMangling); + // It's important to key cache reads off ND, not TD -- the same TD can + // be used with different TemplateArgs, but ND uniquely identifies + // TD / TemplateArg pairs. + ArgBackRefMap::iterator Found = TemplateArgBackReferences.find(ND); + if (Found == TemplateArgBackReferences.end()) { + + TemplateArgStringMap::iterator Found = TemplateArgStrings.find(ND); + if (Found == TemplateArgStrings.end()) { + // Mangle full template name into temporary buffer. + llvm::SmallString<64> TemplateMangling; + llvm::raw_svector_ostream Stream(TemplateMangling); + MicrosoftCXXNameMangler Extra(Context, Stream); + Extra.mangleTemplateInstantiationName(TD, *TemplateArgs); + + // Use the string backref vector to possibly get a back reference. + mangleSourceName(TemplateMangling); + + // Memoize back reference for this type if one exist, else memoize + // the mangling itself. + BackRefVec::iterator StringFound = + llvm::find(NameBackReferences, TemplateMangling); + if (StringFound != NameBackReferences.end()) { + TemplateArgBackReferences[ND] = + StringFound - NameBackReferences.begin(); + } else { + TemplateArgStrings[ND] = + TemplateArgStringStorage.save(TemplateMangling.str()); + } + } else { + Out << Found->second; // Outputs a StringRef. + } + } else { + Out << Found->second; // Outputs a back reference (an int). + } return; } @@ -1242,15 +1280,8 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, case OO_Array_Delete: Out << "?_V"; break; // <operator-name> ::= ?__L # co_await case OO_Coawait: Out << "?__L"; break; - - case OO_Spaceship: { - // FIXME: Once MS picks a mangling, use it. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this three-way comparison operator yet"); - Diags.Report(Loc, DiagID); - break; - } + // <operator-name> ::= ?__M # <=> + case OO_Spaceship: Out << "?__M"; break; case OO_Conditional: { DiagnosticsEngine &Diags = Context.getDiags(); @@ -1268,8 +1299,7 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) { // <source name> ::= <identifier> @ - BackRefVec::iterator Found = - std::find(NameBackReferences.begin(), NameBackReferences.end(), Name); + BackRefVec::iterator Found = llvm::find(NameBackReferences, Name); if (Found == NameBackReferences.end()) { if (NameBackReferences.size() < 10) NameBackReferences.push_back(Name); @@ -1290,11 +1320,13 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( // Always start with the unqualified name. // Templates have their own context for back references. - ArgBackRefMap OuterArgsContext; + ArgBackRefMap OuterFunArgsContext; + ArgBackRefMap OuterTemplateArgsContext; BackRefVec OuterTemplateContext; PassObjectSizeArgsSet OuterPassObjectSizeArgs; NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); mangleUnscopedTemplateName(TD); @@ -1302,7 +1334,8 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); } @@ -1707,8 +1740,8 @@ void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) { } } -void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, - SourceRange Range) { +void MicrosoftCXXNameMangler::mangleFunctionArgumentType(QualType T, + SourceRange Range) { // MSVC will backreference two canonically equivalent types that have slightly // different manglings when mangled alone. @@ -1738,9 +1771,9 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, TypePtr = T.getCanonicalType().getAsOpaquePtr(); } - ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); + ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr); - if (Found == TypeBackReferences.end()) { + if (Found == FunArgBackReferences.end()) { size_t OutSizeBefore = Out.tell(); mangleType(T, Range, QMM_Drop); @@ -1749,9 +1782,9 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, // Only types longer than 1 character are considered // and only 10 back references slots are available: bool LongerThanOneChar = (Out.tell() - OutSizeBefore > 1); - if (LongerThanOneChar && TypeBackReferences.size() < 10) { - size_t Size = TypeBackReferences.size(); - TypeBackReferences[TypePtr] = Size; + if (LongerThanOneChar && FunArgBackReferences.size() < 10) { + size_t Size = FunArgBackReferences.size(); + FunArgBackReferences[TypePtr] = Size; } } else { Out << Found->second; @@ -1761,18 +1794,20 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, void MicrosoftCXXNameMangler::manglePassObjectSizeArg( const PassObjectSizeAttr *POSA) { int Type = POSA->getType(); + bool Dynamic = POSA->isDynamic(); - auto Iter = PassObjectSizeArgs.insert(Type).first; + auto Iter = PassObjectSizeArgs.insert({Type, Dynamic}).first; auto *TypePtr = (const void *)&*Iter; - ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); + ArgBackRefMap::iterator Found = FunArgBackReferences.find(TypePtr); - if (Found == TypeBackReferences.end()) { - mangleArtificialTagType(TTK_Enum, "__pass_object_size" + llvm::utostr(Type), - {"__clang"}); + if (Found == FunArgBackReferences.end()) { + std::string Name = + Dynamic ? "__pass_dynamic_object_size" : "__pass_object_size"; + mangleArtificialTagType(TTK_Enum, Name + llvm::utostr(Type), {"__clang"}); - if (TypeBackReferences.size() < 10) { - size_t Size = TypeBackReferences.size(); - TypeBackReferences[TypePtr] = Size; + if (FunArgBackReferences.size() < 10) { + size_t Size = FunArgBackReferences.size(); + FunArgBackReferences[TypePtr] = Size; } } else { Out << Found->second; @@ -1937,8 +1972,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, // ::= _M # unsigned __int128 // ::= _N # bool // _O # <array in parameter> - // ::= _T # __float80 (Intel) + // ::= _Q # char8_t // ::= _S # char16_t + // ::= _T # __float80 (Intel) // ::= _U # char32_t // ::= _W # wchar_t // ::= _Z # __float80 (Digital Mars) @@ -1999,6 +2035,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, case BuiltinType::Bool: Out << "_N"; break; + case BuiltinType::Char8: + Out << "_Q"; + break; case BuiltinType::Char16: Out << "_S"; break; @@ -2094,7 +2133,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: - case BuiltinType::Char8: case BuiltinType::Float128: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( @@ -2112,7 +2150,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers, // Structors only appear in decls, so at this point we know it's not a // structor type. // FIXME: This may not be lambda-friendly. - if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) { + if (T->getMethodQuals() || T->getRefQualifier() != RQ_None) { Out << "$$A8@@"; mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true); } else { @@ -2161,7 +2199,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, // If this is a C++ instance method, mangle the CVR qualifiers for the // this pointer. if (HasThisQuals) { - Qualifiers Quals = Proto->getTypeQuals(); + Qualifiers Quals = Proto->getMethodQuals(); manglePointerExtQualifiers(Quals, /*PointeeType=*/QualType()); mangleRefQualifier(Proto->getRefQualifier()); mangleQualifiers(Quals, /*IsMember=*/false); @@ -2195,12 +2233,12 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, Out << 'X'; } else if (StructorType == Ctor_CopyingClosure) { // Copy constructor closure always takes an unqualified reference. - mangleArgumentType(getASTContext().getLValueReferenceType( - Proto->getParamType(0) - ->getAs<LValueReferenceType>() - ->getPointeeType(), - /*SpelledAsLValue=*/true), - Range); + mangleFunctionArgumentType(getASTContext().getLValueReferenceType( + Proto->getParamType(0) + ->getAs<LValueReferenceType>() + ->getPointeeType(), + /*SpelledAsLValue=*/true), + Range); Out << '@'; } else { llvm_unreachable("unexpected constructor closure!"); @@ -2242,7 +2280,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, } else { // Happens for function pointer type arguments for example. for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { - mangleArgumentType(Proto->getParamType(I), Range); + mangleFunctionArgumentType(Proto->getParamType(I), Range); // Mangle each pass_object_size parameter as if it's a parameter of enum // type passed directly after the parameter with the pass_object_size // attribute. The aforementioned enum's name is __pass_object_size, and we @@ -2734,10 +2772,12 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, if (T->qual_empty() && !T->isSpecialized()) return mangleType(T->getBaseType(), Range, QMM_Drop); - ArgBackRefMap OuterArgsContext; + ArgBackRefMap OuterFunArgsContext; + ArgBackRefMap OuterTemplateArgsContext; BackRefVec OuterTemplateContext; - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); NameBackReferences.swap(OuterTemplateContext); mangleTagTypeKind(TTK_Struct); @@ -2761,7 +2801,8 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Out << '@'; - TypeBackReferences.swap(OuterArgsContext); + FunArgBackReferences.swap(OuterFunArgsContext); + TemplateArgBackReferences.swap(OuterTemplateArgsContext); NameBackReferences.swap(OuterTemplateContext); } @@ -3154,12 +3195,18 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType( } Mangler.getStream() << RTTIMangling; - // VS2015 CTP6 omits the copy-constructor in the mangled name. This name is, - // in fact, superfluous but I'm not sure the change was made consciously. + // VS2015 and VS2017.1 omit the copy-constructor in the mangled name but + // both older and newer versions include it. + // FIXME: It is known that the Ctor is present in 2013, and in 2017.7 + // (_MSC_VER 1914) and newer, and that it's omitted in 2015 and 2017.4 + // (_MSC_VER 1911), but it's unknown when exactly it reappeared (1914? + // Or 1912, 1913 aleady?). + bool OmitCopyCtor = getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2015) && + !getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2017_7); llvm::SmallString<64> CopyCtorMangling; - if (!getASTContext().getLangOpts().isCompatibleWithMSVC( - LangOptions::MSVC2015) && - CD) { + if (!OmitCopyCtor && CD) { llvm::raw_svector_ostream Stream(CopyCtorMangling); msvc_hashing_ostream MHO(Stream); mangleCXXCtor(CD, CT, MHO); @@ -3457,8 +3504,7 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, } else { const char SpecialChars[] = {',', '/', '\\', ':', '.', ' ', '\n', '\t', '\'', '-'}; - const char *Pos = - std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte); + const char *Pos = llvm::find(SpecialChars, Byte); if (Pos != std::end(SpecialChars)) { Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars)); } else { diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 5b8300893e2d5..5104dc59d621e 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -1,9 +1,8 @@ //===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 42f6a133d7174..09d85102585bd 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -1,9 +1,8 @@ //===- NestedNameSpecifier.cpp - C++ nested name specifiers ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index a4c344ce0a9b1..3b89c630b451e 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -1,9 +1,8 @@ //===-- ODRHash.cpp - Hashing to diagnose ODR failures ----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -72,8 +71,13 @@ void ODRHash::AddDeclarationNameImpl(DeclarationName Name) { AddBoolean(S.isKeywordSelector()); AddBoolean(S.isUnarySelector()); unsigned NumArgs = S.getNumArgs(); + ID.AddInteger(NumArgs); for (unsigned i = 0; i < NumArgs; ++i) { - AddIdentifierInfo(S.getIdentifierInfoForSlot(i)); + const IdentifierInfo *II = S.getIdentifierInfoForSlot(i); + AddBoolean(II); + if (II) { + AddIdentifierInfo(II); + } } break; } @@ -141,6 +145,7 @@ void ODRHash::AddTemplateName(TemplateName Name) { break; // TODO: Support these cases. case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: case TemplateName::QualifiedTemplate: case TemplateName::DependentTemplate: case TemplateName::SubstTemplateTemplateParm: @@ -696,7 +701,52 @@ public: ID.AddInteger(Quals.getAsOpaqueValue()); } + // Return the RecordType if the typedef only strips away a keyword. + // Otherwise, return the original type. + static const Type *RemoveTypedef(const Type *T) { + const auto *TypedefT = dyn_cast<TypedefType>(T); + if (!TypedefT) { + return T; + } + + const TypedefNameDecl *D = TypedefT->getDecl(); + QualType UnderlyingType = D->getUnderlyingType(); + + if (UnderlyingType.hasLocalQualifiers()) { + return T; + } + + const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType); + if (!ElaboratedT) { + return T; + } + + if (ElaboratedT->getQualifier() != nullptr) { + return T; + } + + QualType NamedType = ElaboratedT->getNamedType(); + if (NamedType.hasLocalQualifiers()) { + return T; + } + + const auto *RecordT = dyn_cast<RecordType>(NamedType); + if (!RecordT) { + return T; + } + + const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); + const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); + if (!TypedefII || !RecordII || + TypedefII->getName() != RecordII->getName()) { + return T; + } + + return RecordT; + } + void Visit(const Type *T) { + T = RemoveTypedef(T); ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); } @@ -704,14 +754,36 @@ public: void VisitType(const Type *T) {} void VisitAdjustedType(const AdjustedType *T) { - AddQualType(T->getOriginalType()); - AddQualType(T->getAdjustedType()); + QualType Original = T->getOriginalType(); + QualType Adjusted = T->getAdjustedType(); + + // The original type and pointee type can be the same, as in the case of + // function pointers decaying to themselves. Set a bool and only process + // the type once, to prevent doubling the work. + SplitQualType split = Adjusted.split(); + if (auto Pointer = dyn_cast<PointerType>(split.Ty)) { + if (Pointer->getPointeeType() == Original) { + Hash.AddBoolean(true); + ID.AddInteger(split.Quals.getAsOpaqueValue()); + AddQualType(Original); + VisitType(T); + return; + } + } + + // The original type and pointee type are different, such as in the case + // of a array decaying to an element pointer. Set a bool to false and + // process both types. + Hash.AddBoolean(false); + AddQualType(Original); + AddQualType(Adjusted); + VisitType(T); } void VisitDecayedType(const DecayedType *T) { - AddQualType(T->getDecayedType()); - AddQualType(T->getPointeeType()); + // getDecayedType and getPointeeType are derived from getAdjustedType + // and don't need to be separately processed. VisitAdjustedType(T); } diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp index 76098f15bf36f..9d8a7ebc3023e 100644 --- a/lib/AST/OpenMPClause.cpp +++ b/lib/AST/OpenMPClause.cpp @@ -1,9 +1,8 @@ //===- OpenMPClause.cpp - Classes for OpenMP clauses ----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -36,6 +35,20 @@ OMPClause::child_range OMPClause::children() { llvm_unreachable("unknown OMPClause"); } +OMPClause::child_range OMPClause::used_children() { + switch (getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return static_cast<Class *>(this)->used_children(); +#include "clang/Basic/OpenMPKinds.def" + case OMPC_threadprivate: + case OMPC_uniform: + case OMPC_unknown: + break; + } + llvm_unreachable("unknown OMPClause"); +} + OMPClauseWithPreInit *OMPClauseWithPreInit::get(OMPClause *C) { auto *Res = OMPClauseWithPreInit::get(const_cast<const OMPClause *>(C)); return Res ? const_cast<OMPClauseWithPreInit *>(Res) : nullptr; @@ -74,6 +87,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_final: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: + case OMPC_allocate: case OMPC_collapse: case OMPC_private: case OMPC_shared: @@ -145,6 +160,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_num_threads: case OMPC_safelen: case OMPC_simdlen: + case OMPC_allocator: + case OMPC_allocate: case OMPC_collapse: case OMPC_private: case OMPC_shared: @@ -192,6 +209,25 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) return nullptr; } +/// Gets the address of the original, non-captured, expression used in the +/// clause as the preinitializer. +static Stmt **getAddrOfExprAsWritten(Stmt *S) { + if (!S) + return nullptr; + if (auto *DS = dyn_cast<DeclStmt>(S)) { + assert(DS->isSingleDecl() && "Only single expression must be captured."); + if (auto *OED = dyn_cast<OMPCapturedExprDecl>(DS->getSingleDecl())) + return OED->getInitAddress(); + } + return nullptr; +} + +OMPClause::child_range OMPIfClause::used_children() { + if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt())) + return child_range(C, C + 1); + return child_range(&Condition, &Condition + 1); +} + OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num, unsigned NumLoops, SourceLocation StartLoc, @@ -698,6 +734,25 @@ OMPInReductionClause *OMPInReductionClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPInReductionClause(N); } +OMPAllocateClause * +OMPAllocateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, Expr *Allocator, + SourceLocation ColonLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + // Allocate space for private variables and initializer expressions. + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size())); + auto *Clause = new (Mem) OMPAllocateClause(StartLoc, LParenLoc, Allocator, + ColonLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPAllocateClause *OMPAllocateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N)); + return new (Mem) OMPAllocateClause(N); +} + OMPFlushClause *OMPFlushClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -791,24 +846,23 @@ unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber( return TotalNum; } -OMPMapClause * -OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc, - ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations, - MappableExprComponentListsRef ComponentLists, - ArrayRef<OpenMPMapModifierKind> MapModifiers, - ArrayRef<SourceLocation> MapModifiersLoc, - OpenMPMapClauseKind Type, bool TypeIsImplicit, - SourceLocation TypeLoc) { - unsigned NumVars = Vars.size(); - unsigned NumUniqueDeclarations = - getUniqueDeclarationsTotalNumber(Declarations); - unsigned NumComponentLists = ComponentLists.size(); - unsigned NumComponents = getComponentsTotalNumber(ComponentLists); +OMPMapClause *OMPMapClause::Create( + const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars, + ArrayRef<ValueDecl *> Declarations, + MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs, + ArrayRef<OpenMPMapModifierKind> MapModifiers, + ArrayRef<SourceLocation> MapModifiersLoc, + NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId, + OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) { + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); // We need to allocate: - // NumVars x Expr* - we have an original list expression for each clause list - // entry. + // 2 x NumVars x Expr* - we have an original list expression and an associated + // user-defined mapper for each clause list entry. // NumUniqueDeclarations x ValueDecl* - unique base declarations associated // with each component list. // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the @@ -819,47 +873,47 @@ OMPMapClause::Create(const ASTContext &C, SourceLocation StartLoc, void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - OMPMapClause *Clause = new (Mem) OMPMapClause( - MapModifiers, MapModifiersLoc, Type, TypeIsImplicit, TypeLoc, StartLoc, - LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, NumComponentLists, - NumComponents); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + OMPMapClause *Clause = new (Mem) + OMPMapClause(MapModifiers, MapModifiersLoc, UDMQualifierLoc, MapperId, + Type, TypeIsImplicit, TypeLoc, Locs, Sizes); Clause->setVarRefs(Vars); + Clause->setUDMapperRefs(UDMapperRefs); Clause->setClauseInfo(Declarations, ComponentLists); Clause->setMapType(Type); Clause->setMapLoc(TypeLoc); return Clause; } -OMPMapClause *OMPMapClause::CreateEmpty(const ASTContext &C, unsigned NumVars, - unsigned NumUniqueDeclarations, - unsigned NumComponentLists, - unsigned NumComponents) { +OMPMapClause * +OMPMapClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - return new (Mem) OMPMapClause(NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); -} - -OMPToClause *OMPToClause::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef<Expr *> Vars, - ArrayRef<ValueDecl *> Declarations, - MappableExprComponentListsRef ComponentLists) { - unsigned NumVars = Vars.size(); - unsigned NumUniqueDeclarations = - getUniqueDeclarationsTotalNumber(Declarations); - unsigned NumComponentLists = ComponentLists.size(); - unsigned NumComponents = getComponentsTotalNumber(ComponentLists); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPMapClause(Sizes); +} + +OMPToClause *OMPToClause::Create( + const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars, + ArrayRef<ValueDecl *> Declarations, + MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs, + NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) { + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); // We need to allocate: - // NumVars x Expr* - we have an original list expression for each clause list - // entry. + // 2 x NumVars x Expr* - we have an original list expression and an associated + // user-defined mapper for each clause list entry. // NumUniqueDeclarations x ValueDecl* - unique base declarations associated // with each component list. // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the @@ -870,45 +924,43 @@ OMPToClause *OMPToClause::Create(const ASTContext &C, SourceLocation StartLoc, void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); - OMPToClause *Clause = new (Mem) - OMPToClause(StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + auto *Clause = new (Mem) OMPToClause(UDMQualifierLoc, MapperId, Locs, Sizes); Clause->setVarRefs(Vars); + Clause->setUDMapperRefs(UDMapperRefs); Clause->setClauseInfo(Declarations, ComponentLists); return Clause; } -OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C, unsigned NumVars, - unsigned NumUniqueDeclarations, - unsigned NumComponentLists, - unsigned NumComponents) { +OMPToClause *OMPToClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - return new (Mem) OMPToClause(NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); -} - -OMPFromClause * -OMPFromClause::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc, - ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations, - MappableExprComponentListsRef ComponentLists) { - unsigned NumVars = Vars.size(); - unsigned NumUniqueDeclarations = - getUniqueDeclarationsTotalNumber(Declarations); - unsigned NumComponentLists = ComponentLists.size(); - unsigned NumComponents = getComponentsTotalNumber(ComponentLists); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPToClause(Sizes); +} + +OMPFromClause *OMPFromClause::Create( + const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars, + ArrayRef<ValueDecl *> Declarations, + MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs, + NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId) { + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); // We need to allocate: - // NumVars x Expr* - we have an original list expression for each clause list - // entry. + // 2 x NumVars x Expr* - we have an original list expression and an associated + // user-defined mapper for each clause list entry. // NumUniqueDeclarations x ValueDecl* - unique base declarations associated // with each component list. // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the @@ -919,29 +971,29 @@ OMPFromClause::Create(const ASTContext &C, SourceLocation StartLoc, void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); - OMPFromClause *Clause = new (Mem) - OMPFromClause(StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + auto *Clause = + new (Mem) OMPFromClause(UDMQualifierLoc, MapperId, Locs, Sizes); Clause->setVarRefs(Vars); + Clause->setUDMapperRefs(UDMapperRefs); Clause->setClauseInfo(Declarations, ComponentLists); return Clause; } -OMPFromClause *OMPFromClause::CreateEmpty(const ASTContext &C, unsigned NumVars, - unsigned NumUniqueDeclarations, - unsigned NumComponentLists, - unsigned NumComponents) { +OMPFromClause * +OMPFromClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - return new (Mem) OMPFromClause(NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPFromClause(Sizes); } void OMPUseDevicePtrClause::setPrivateCopies(ArrayRef<Expr *> VL) { @@ -957,15 +1009,15 @@ void OMPUseDevicePtrClause::setInits(ArrayRef<Expr *> VL) { } OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create( - const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef<Expr *> Vars, ArrayRef<Expr *> PrivateVars, - ArrayRef<Expr *> Inits, ArrayRef<ValueDecl *> Declarations, + const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars, + ArrayRef<Expr *> PrivateVars, ArrayRef<Expr *> Inits, + ArrayRef<ValueDecl *> Declarations, MappableExprComponentListsRef ComponentLists) { - unsigned NumVars = Vars.size(); - unsigned NumUniqueDeclarations = - getUniqueDeclarationsTotalNumber(Declarations); - unsigned NumComponentLists = ComponentLists.size(); - unsigned NumComponents = getComponentsTotalNumber(ComponentLists); + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); // We need to allocate: // 3 x NumVars x Expr* - we have an original list expression for each clause @@ -980,12 +1032,11 @@ OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create( void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - 3 * NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); + 3 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); - OMPUseDevicePtrClause *Clause = new (Mem) OMPUseDevicePtrClause( - StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + OMPUseDevicePtrClause *Clause = new (Mem) OMPUseDevicePtrClause(Locs, Sizes); Clause->setVarRefs(Vars); Clause->setPrivateCopies(PrivateVars); @@ -994,29 +1045,28 @@ OMPUseDevicePtrClause *OMPUseDevicePtrClause::Create( return Clause; } -OMPUseDevicePtrClause *OMPUseDevicePtrClause::CreateEmpty( - const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, - unsigned NumComponentLists, unsigned NumComponents) { +OMPUseDevicePtrClause * +OMPUseDevicePtrClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - 3 * NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - return new (Mem) OMPUseDevicePtrClause(NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + 3 * Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPUseDevicePtrClause(Sizes); } OMPIsDevicePtrClause * -OMPIsDevicePtrClause::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation EndLoc, +OMPIsDevicePtrClause::Create(const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars, ArrayRef<ValueDecl *> Declarations, MappableExprComponentListsRef ComponentLists) { - unsigned NumVars = Vars.size(); - unsigned NumUniqueDeclarations = - getUniqueDeclarationsTotalNumber(Declarations); - unsigned NumComponentLists = ComponentLists.size(); - unsigned NumComponents = getComponentsTotalNumber(ComponentLists); + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); // We need to allocate: // NumVars x Expr* - we have an original list expression for each clause list @@ -1031,28 +1081,27 @@ OMPIsDevicePtrClause::Create(const ASTContext &C, SourceLocation StartLoc, void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); + Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); - OMPIsDevicePtrClause *Clause = new (Mem) OMPIsDevicePtrClause( - StartLoc, LParenLoc, EndLoc, NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + OMPIsDevicePtrClause *Clause = new (Mem) OMPIsDevicePtrClause(Locs, Sizes); Clause->setVarRefs(Vars); Clause->setClauseInfo(Declarations, ComponentLists); return Clause; } -OMPIsDevicePtrClause *OMPIsDevicePtrClause::CreateEmpty( - const ASTContext &C, unsigned NumVars, unsigned NumUniqueDeclarations, - unsigned NumComponentLists, unsigned NumComponents) { +OMPIsDevicePtrClause * +OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { void *Mem = C.Allocate( totalSizeToAlloc<Expr *, ValueDecl *, unsigned, OMPClauseMappableExprCommon::MappableComponent>( - NumVars, NumUniqueDeclarations, - NumUniqueDeclarations + NumComponentLists, NumComponents)); - return new (Mem) OMPIsDevicePtrClause(NumVars, NumUniqueDeclarations, - NumComponentLists, NumComponents); + Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPIsDevicePtrClause(Sizes); } //===----------------------------------------------------------------------===// @@ -1091,6 +1140,12 @@ void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPAllocatorClause(OMPAllocatorClause *Node) { + OS << "allocator("; + Node->getAllocator()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPCollapseClause(OMPCollapseClause *Node) { OS << "collapse("; Node->getNumForLoops()->printPretty(OS, nullptr, Policy, 0); @@ -1261,6 +1316,21 @@ void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { } } +void OMPClausePrinter::VisitOMPAllocateClause(OMPAllocateClause *Node) { + if (Node->varlist_empty()) + return; + OS << "allocate"; + if (Expr *Allocator = Node->getAllocator()) { + OS << "("; + Allocator->printPretty(OS, nullptr, Policy, 0); + OS << ":"; + VisitOMPClauseList(Node, ' '); + } else { + VisitOMPClauseList(Node, '('); + } + OS << ")"; +} + void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { if (!Node->varlist_empty()) { OS << "private"; @@ -1432,6 +1502,14 @@ void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) { if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) { OS << getOpenMPSimpleClauseTypeName(OMPC_map, Node->getMapTypeModifier(I)); + if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper) { + OS << '('; + NestedNameSpecifier *MapperNNS = + Node->getMapperQualifierLoc().getNestedNameSpecifier(); + if (MapperNNS) + MapperNNS->print(OS, Policy); + OS << Node->getMapperIdInfo() << ')'; + } OS << ','; } } @@ -1446,7 +1524,19 @@ void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) { void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) { if (!Node->varlist_empty()) { OS << "to"; - VisitOMPClauseList(Node, '('); + DeclarationNameInfo MapperId = Node->getMapperIdInfo(); + if (MapperId.getName() && !MapperId.getName().isEmpty()) { + OS << '('; + OS << "mapper("; + NestedNameSpecifier *MapperNNS = + Node->getMapperQualifierLoc().getNestedNameSpecifier(); + if (MapperNNS) + MapperNNS->print(OS, Policy); + OS << MapperId << "):"; + VisitOMPClauseList(Node, ' '); + } else { + VisitOMPClauseList(Node, '('); + } OS << ")"; } } @@ -1454,7 +1544,19 @@ void OMPClausePrinter::VisitOMPToClause(OMPToClause *Node) { void OMPClausePrinter::VisitOMPFromClause(OMPFromClause *Node) { if (!Node->varlist_empty()) { OS << "from"; - VisitOMPClauseList(Node, '('); + DeclarationNameInfo MapperId = Node->getMapperIdInfo(); + if (MapperId.getName() && !MapperId.getName().isEmpty()) { + OS << '('; + OS << "mapper("; + NestedNameSpecifier *MapperNNS = + Node->getMapperQualifierLoc().getNestedNameSpecifier(); + if (MapperNNS) + MapperNNS->print(OS, Policy); + OS << MapperId << "):"; + VisitOMPClauseList(Node, ' '); + } else { + VisitOMPClauseList(Node, '('); + } OS << ")"; } } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 88c178aa372fc..2ff5c9d8aeb57 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -1,9 +1,8 @@ //===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -84,6 +83,18 @@ static void BuildParentMap(MapTy& M, Stmt* S, } break; } + case Stmt::CapturedStmtClass: + for (Stmt *SubStmt : S->children()) { + if (SubStmt) { + M[SubStmt] = S; + BuildParentMap(M, SubStmt, OVMode); + } + } + if (Stmt *SubStmt = cast<CapturedStmt>(S)->getCapturedStmt()) { + M[SubStmt] = S; + BuildParentMap(M, SubStmt, OVMode); + } + break; default: for (Stmt *SubStmt : S->children()) { if (SubStmt) { diff --git a/lib/AST/PrintfFormatString.cpp b/lib/AST/PrintfFormatString.cpp index e0a0c5b7582aa..a1207aae5aa25 100644 --- a/lib/AST/PrintfFormatString.cpp +++ b/lib/AST/PrintfFormatString.cpp @@ -1,9 +1,8 @@ //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -316,7 +315,11 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; - case 'n': k = ConversionSpecifier::nArg; break; + case 'n': + // Not handled, but reserved in OpenCL. + if (!LO.OpenCL) + k = ConversionSpecifier::nArg; + break; case 'o': k = ConversionSpecifier::oArg; break; case 'p': k = ConversionSpecifier::pArg; break; case 's': k = ConversionSpecifier::sArg; break; @@ -487,10 +490,12 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, // GNU extension. return Ctx.LongLongTy; case LengthModifier::None: + case LengthModifier::AsShortLong: return Ctx.IntTy; case LengthModifier::AsInt32: return ArgType(Ctx.IntTy, "__int32"); - case LengthModifier::AsChar: return ArgType::AnyCharTy; + case LengthModifier::AsChar: + return ArgType::AnyCharTy; case LengthModifier::AsShort: return Ctx.ShortTy; case LengthModifier::AsLong: return Ctx.LongTy; case LengthModifier::AsLongLong: @@ -521,6 +526,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, // GNU extension. return Ctx.UnsignedLongLongTy; case LengthModifier::None: + case LengthModifier::AsShortLong: return Ctx.UnsignedIntTy; case LengthModifier::AsInt32: return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); @@ -550,6 +556,18 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, } if (CS.isDoubleArg()) { + if (!VectorNumElts.isInvalid()) { + switch (LM.getKind()) { + case LengthModifier::AsShort: + return Ctx.HalfTy; + case LengthModifier::AsShortLong: + return Ctx.FloatTy; + case LengthModifier::AsLong: + default: + return Ctx.DoubleTy; + } + } + if (LM.getKind() == LengthModifier::AsLongDouble) return Ctx.LongDoubleTy; return Ctx.DoubleTy; @@ -583,6 +601,8 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsInt64: case LengthModifier::AsWide: return ArgType::Invalid(); + case LengthModifier::AsShortLong: + llvm_unreachable("only used for OpenCL which doesn not handle nArg"); } } @@ -761,10 +781,13 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: + LM.setKind(VectorNumElts.isInvalid() ? + LengthModifier::None : LengthModifier::AsShortLong); + break; case BuiltinType::Double: - LM.setKind(LengthModifier::None); + LM.setKind(VectorNumElts.isInvalid() ? + LengthModifier::None : LengthModifier::AsLong); break; - case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: @@ -797,7 +820,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, namedTypeToLengthModifier(QT, LM); // If fixing the length modifier was enough, we might be done. - if (hasValidLengthModifier(Ctx.getTargetInfo())) { + if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { // If we're going to offer a fix anyway, make sure the sign matches. switch (CS.getKind()) { case ConversionSpecifier::uArg: diff --git a/lib/AST/QualTypeNames.cpp b/lib/AST/QualTypeNames.cpp index 8b605ef295a02..f28f00171cce3 100644 --- a/lib/AST/QualTypeNames.cpp +++ b/lib/AST/QualTypeNames.cpp @@ -1,11 +1,8 @@ //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===// // -// The LLVM Compiler Infrastructure -// -//===----------------------------------------------------------------------===// -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -382,6 +379,19 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, return QT; } + if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) { + // Get the qualifiers. + Qualifiers Quals = QT.getQualifiers(); + // Fully qualify the pointee and class types. + QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); + QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx, + WithGlobalNsPrefix); + QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); + // Add back the qualifiers. + QT = Ctx.getQualifiedType(QT, Quals); + return QT; + } + // In case of myType& we need to strip the reference first, fully // qualify and attach the reference once again. if (isa<ReferenceType>(QT.getTypePtr())) { diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index ab873a3964195..df53b7fa10047 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -1,9 +1,8 @@ //===--- RawCommentList.cpp - Processing raw comments -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index 9db23d50d0af2..e7b500e1902d7 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -1,9 +1,8 @@ //===- RecordLayout.cpp - Layout information for a struct/union -----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 62dc22c814033..2a3419a0cec3d 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -1,9 +1,8 @@ //=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -128,9 +127,10 @@ class EmptySubobjectMap { CharUnits Offset, bool PlacingEmptyBase); void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - CharUnits Offset); - void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset); + const CXXRecordDecl *Class, CharUnits Offset, + bool PlacingOverlappingField); + void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset, + bool PlacingOverlappingField); /// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty /// subobjects beyond the given offset. @@ -239,7 +239,7 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, return true; const ClassVectorTy &Classes = I->second; - if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end()) + if (llvm::find(Classes, RD) == Classes.end()) return true; // There is already an empty class of the same type at this offset. @@ -255,7 +255,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, // If we have empty structures inside a union, we can assign both // the same offset. Just avoid pushing them twice in the list. ClassVectorTy &Classes = EmptyClassOffsets[Offset]; - if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) + if (llvm::is_contained(Classes, RD)) return; Classes.push_back(RD); @@ -352,7 +352,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, continue; CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); - UpdateEmptyFieldSubobjects(*I, FieldOffset); + UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingEmptyBase); } } @@ -472,20 +472,25 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, return false; // We are able to place the member variable at this offset. - // Make sure to update the empty base subobject map. - UpdateEmptyFieldSubobjects(FD, Offset); + // Make sure to update the empty field subobject map. + UpdateEmptyFieldSubobjects(FD, Offset, FD->hasAttr<NoUniqueAddressAttr>()); return true; } -void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - CharUnits Offset) { +void EmptySubobjectMap::UpdateEmptyFieldSubobjects( + const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset, + bool PlacingOverlappingField) { // We know that the only empty subobjects that can conflict with empty - // field subobjects are subobjects of empty bases that can be placed at offset - // zero. Because of this, we only need to keep track of empty field - // subobjects with offsets less than the size of the largest empty - // subobject for our class. - if (Offset >= SizeOfLargestEmptySubobject) + // field subobjects are subobjects of empty bases and potentially-overlapping + // fields that can be placed at offset zero. Because of this, we only need to + // keep track of empty field subobjects with offsets less than the size of + // the largest empty subobject for our class. + // + // (Proof: we will only consider placing a subobject at offset zero or at + // >= the current dsize. The only cases where the earlier subobject can be + // placed beyond the end of dsize is if it's an empty base or a + // potentially-overlapping field.) + if (!PlacingOverlappingField && Offset >= SizeOfLargestEmptySubobject) return; AddSubobjectAtOffset(RD, Offset); @@ -500,7 +505,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); - UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset); + UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset, + PlacingOverlappingField); } if (RD == Class) { @@ -509,7 +515,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *VBaseDecl = Base.getType()->getAsCXXRecordDecl(); CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); - UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset); + UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset, + PlacingOverlappingField); } } @@ -522,15 +529,15 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); - UpdateEmptyFieldSubobjects(*I, FieldOffset); + UpdateEmptyFieldSubobjects(*I, FieldOffset, PlacingOverlappingField); } } -void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, - CharUnits Offset) { +void EmptySubobjectMap::UpdateEmptyFieldSubobjects( + const FieldDecl *FD, CharUnits Offset, bool PlacingOverlappingField) { QualType T = FD->getType(); if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { - UpdateEmptyFieldSubobjects(RD, RD, Offset); + UpdateEmptyFieldSubobjects(RD, RD, Offset, PlacingOverlappingField); return; } @@ -553,10 +560,12 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, // offset zero. Because of this, we only need to keep track of empty field // subobjects with offsets less than the size of the largest empty // subobject for our class. - if (ElementOffset >= SizeOfLargestEmptySubobject) + if (!PlacingOverlappingField && + ElementOffset >= SizeOfLargestEmptySubobject) return; - UpdateEmptyFieldSubobjects(RD, RD, ElementOffset); + UpdateEmptyFieldSubobjects(RD, RD, ElementOffset, + PlacingOverlappingField); ElementOffset += Layout.getSize(); } } @@ -623,6 +632,10 @@ protected: CharUnits NonVirtualSize; CharUnits NonVirtualAlignment; + /// If we've laid out a field but not included its tail padding in Size yet, + /// this is the size up to the end of that field. + CharUnits PaddedFieldSize; + /// PrimaryBase - the primary base class (if one exists) of the class /// we're laying out. const CXXRecordDecl *PrimaryBase; @@ -671,7 +684,8 @@ protected: UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), - NonVirtualAlignment(CharUnits::One()), PrimaryBase(nullptr), + NonVirtualAlignment(CharUnits::One()), + PaddedFieldSize(CharUnits::Zero()), PrimaryBase(nullptr), PrimaryBaseIsVirtual(false), HasOwnVFPtr(false), HasPackedField(false), FirstNearlyEmptyVBase(nullptr) {} @@ -981,7 +995,6 @@ void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment( // Round up the current record size to pointer alignment. setSize(getSize().alignTo(BaseAlign)); - setDataSize(getSize()); // Update the alignment. UpdateAlignment(BaseAlign, UnpackedBaseAlign); @@ -1173,6 +1186,7 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { // Query the external layout to see if it provides an offset. bool HasExternalLayout = false; if (UseExternalLayout) { + // FIXME: This appears to be reversed. if (Base->IsVirtual) HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset); else @@ -1343,8 +1357,8 @@ void ItaniumRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { // We start laying out ivars not at the end of the superclass // structure, but at the next byte following the last field. - setSize(SL.getDataSize()); - setDataSize(getSize()); + setDataSize(SL.getDataSize()); + setSize(getDataSize()); } InitializeLayout(D); @@ -1730,32 +1744,49 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnfilledBitsInLastUnit = 0; LastBitfieldTypeSize = 0; + auto *FieldClass = D->getType()->getAsCXXRecordDecl(); + bool PotentiallyOverlapping = D->hasAttr<NoUniqueAddressAttr>() && FieldClass; + bool IsOverlappingEmptyField = PotentiallyOverlapping && FieldClass->isEmpty(); bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); - CharUnits FieldOffset = - IsUnion ? CharUnits::Zero() : getDataSize(); + + CharUnits FieldOffset = (IsUnion || IsOverlappingEmptyField) + ? CharUnits::Zero() + : getDataSize(); CharUnits FieldSize; CharUnits FieldAlign; + // The amount of this class's dsize occupied by the field. + // This is equal to FieldSize unless we're permitted to pack + // into the field's tail padding. + CharUnits EffectiveFieldSize; if (D->getType()->isIncompleteArrayType()) { // This is a flexible array member; we can't directly // query getTypeInfo about these, so we figure it out here. // Flexible array members don't have any size, but they // have to be aligned appropriately for their element type. - FieldSize = CharUnits::Zero(); + EffectiveFieldSize = FieldSize = CharUnits::Zero(); const ArrayType* ATy = Context.getAsArrayType(D->getType()); FieldAlign = Context.getTypeAlignInChars(ATy->getElementType()); } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType()); - FieldSize = + EffectiveFieldSize = FieldSize = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS)); FieldAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(AS)); } else { std::pair<CharUnits, CharUnits> FieldInfo = Context.getTypeInfoInChars(D->getType()); - FieldSize = FieldInfo.first; + EffectiveFieldSize = FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; + // A potentially-overlapping field occupies its dsize or nvsize, whichever + // is larger. + if (PotentiallyOverlapping) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(FieldClass); + EffectiveFieldSize = + std::max(Layout.getNonVirtualSize(), Layout.getDataSize()); + } + if (IsMsStruct) { // If MS bitfield layout is required, figure out what type is being // laid out and align the field to the width of that type. @@ -1835,7 +1866,12 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // Check if we can place the field at this offset. while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) { // We couldn't place the field at the offset. Try again at a new offset. - FieldOffset += FieldAlign; + // We try offset 0 (for an empty field) and then dsize(C) onwards. + if (FieldOffset == CharUnits::Zero() && + getDataSize() != CharUnits::Zero()) + FieldOffset = getDataSize().alignTo(FieldAlign); + else + FieldOffset += FieldAlign; } } } @@ -1854,18 +1890,23 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, if (FieldSize % ASanAlignment) ExtraSizeForAsan += ASanAlignment - CharUnits::fromQuantity(FieldSize % ASanAlignment); - FieldSize += ExtraSizeForAsan; + EffectiveFieldSize = FieldSize = FieldSize + ExtraSizeForAsan; } // Reserve space for this field. - uint64_t FieldSizeInBits = Context.toBits(FieldSize); - if (IsUnion) - setDataSize(std::max(getDataSizeInBits(), FieldSizeInBits)); - else - setDataSize(FieldOffset + FieldSize); + if (!IsOverlappingEmptyField) { + uint64_t EffectiveFieldSizeInBits = Context.toBits(EffectiveFieldSize); + if (IsUnion) + setDataSize(std::max(getDataSizeInBits(), EffectiveFieldSizeInBits)); + else + setDataSize(FieldOffset + EffectiveFieldSize); - // Update the size. - setSize(std::max(getSizeInBits(), getDataSizeInBits())); + PaddedFieldSize = std::max(PaddedFieldSize, FieldOffset + FieldSize); + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + } else { + setSize(std::max(getSizeInBits(), + (uint64_t)Context.toBits(FieldOffset + FieldSize))); + } // Remember max struct/class alignment. UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign); @@ -1886,6 +1927,10 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { setSize(CharUnits::One()); } + // If we have any remaining field tail padding, include that in the overall + // size. + setSize(std::max(getSizeInBits(), (uint64_t)Context.toBits(PaddedFieldSize))); + // Finally, round the size of the record up to the alignment of the // record itself. uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit; @@ -2693,7 +2738,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { auto FieldBitOffset = External.getExternalFieldOffset(FD); placeFieldAtBitOffset(FieldBitOffset); auto NewSize = Context.toCharUnitsFromBits( - llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth())); + llvm::alignDown(FieldBitOffset, Context.toBits(Info.Alignment)) + + Context.toBits(Info.Size)); Size = std::max(Size, NewSize); Alignment = std::max(Alignment, Info.Alignment); } else if (IsUnion) { @@ -2742,12 +2788,17 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { CharUnits InjectionSite = VBPtrOffset; // But before we do, make sure it's properly aligned. VBPtrOffset = VBPtrOffset.alignTo(PointerInfo.Alignment); + // Determine where the first field should be laid out after the vbptr. + CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; // Shift everything after the vbptr down, unless we're using an external // layout. - if (UseExternalLayout) + if (UseExternalLayout) { + // It is possible that there were no fields or bases located after vbptr, + // so the size was not adjusted before. + if (Size < FieldStart) + Size = FieldStart; return; - // Determine where the first field should be laid out after the vbptr. - CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; + } // Make sure that the amount we push the fields back by is a multiple of the // alignment. CharUnits Offset = (FieldStart - InjectionSite) @@ -2772,8 +2823,14 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) { if (HasVBPtr) VBPtrOffset += Offset; - if (UseExternalLayout) + if (UseExternalLayout) { + // The class may have no bases or fields, but still have a vfptr + // (e.g. it's an interface class). The size was not correctly set before + // in this case. + if (FieldOffsets.empty() && Bases.empty()) + Size += Offset; return; + } Size += Offset; @@ -3276,10 +3333,10 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, } // Sort nvbases by offset. - std::stable_sort(Bases.begin(), Bases.end(), - [&](const CXXRecordDecl *L, const CXXRecordDecl *R) { - return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R); - }); + llvm::stable_sort( + Bases, [&](const CXXRecordDecl *L, const CXXRecordDecl *R) { + return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R); + }); // Dump (non-virtual) bases for (const CXXRecordDecl *Base : Bases) { diff --git a/lib/AST/ScanfFormatString.cpp b/lib/AST/ScanfFormatString.cpp index 08ba7a7a4f5c6..8d763f28e57fd 100644 --- a/lib/AST/ScanfFormatString.cpp +++ b/lib/AST/ScanfFormatString.cpp @@ -1,9 +1,8 @@ //= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -143,7 +142,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, } // Look for the length modifier. - if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) { + if (ParseLengthModifier(FS, I, E, LO, /*IsScanf=*/true) && I == E) { // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; @@ -262,9 +261,10 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsInt32: case LengthModifier::AsInt3264: case LengthModifier::AsWide: + case LengthModifier::AsShortLong: return ArgType::Invalid(); } - llvm_unreachable("Unsupported LenghtModifier Type"); + llvm_unreachable("Unsupported LengthModifier Type"); // Unsigned int. case ConversionSpecifier::oArg: @@ -302,9 +302,10 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsInt32: case LengthModifier::AsInt3264: case LengthModifier::AsWide: + case LengthModifier::AsShortLong: return ArgType::Invalid(); } - llvm_unreachable("Unsupported LenghtModifier Type"); + llvm_unreachable("Unsupported LengthModifier Type"); // Float. case ConversionSpecifier::aArg: @@ -397,6 +398,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsInt32: case LengthModifier::AsInt3264: case LengthModifier::AsWide: + case LengthModifier::AsShortLong: return ArgType::Invalid(); } @@ -502,7 +504,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, namedTypeToLengthModifier(PT, LM); // If fixing the length modifier was enough, we are done. - if (hasValidLengthModifier(Ctx.getTargetInfo())) { + if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { const analyze_scanf::ArgType &AT = getArgType(Ctx); if (AT.isValid() && AT.matchesType(Ctx, QT)) return true; diff --git a/lib/AST/SelectorLocationsKind.cpp b/lib/AST/SelectorLocationsKind.cpp index 8b72c85d7ef70..2c34c9c60c2b2 100644 --- a/lib/AST/SelectorLocationsKind.cpp +++ b/lib/AST/SelectorLocationsKind.cpp @@ -1,9 +1,8 @@ //===--- SelectorLocationsKind.cpp - Kind of selector locations -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 116291bfa1efb..0a4d403106bd4 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1,9 +1,8 @@ //===- Stmt.cpp - Statement AST Node Implementation -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -118,30 +117,6 @@ void Stmt::EnableStatistics() { StatisticsEnabled = true; } -Stmt *Stmt::IgnoreImplicit() { - Stmt *s = this; - - Stmt *lasts = nullptr; - - while (s != lasts) { - lasts = s; - - if (auto *fe = dyn_cast<FullExpr>(s)) - s = fe->getSubExpr(); - - if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) - s = mte->GetTemporaryExpr(); - - if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) - s = bte->getSubExpr(); - - if (auto *ice = dyn_cast<ImplicitCastExpr>(s)) - s = ice->getSubExpr(); - } - - return s; -} - /// Skip no-op (attributed, compound) container stmts and skip captured /// stmt at the top, if \a IgnoreCaptured is true. Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) { @@ -345,6 +320,23 @@ CompoundStmt *CompoundStmt::CreateEmpty(const ASTContext &C, return New; } +const Expr *ValueStmt::getExprStmt() const { + const Stmt *S = this; + do { + if (const auto *E = dyn_cast<Expr>(S)) + return E; + + if (const auto *LS = dyn_cast<LabelStmt>(S)) + S = LS->getSubStmt(); + else if (const auto *AS = dyn_cast<AttributedStmt>(S)) + S = AS->getSubStmt(); + else + llvm_unreachable("unknown kind of ValueStmt"); + } while (isa<ValueStmt>(S)); + + return nullptr; +} + const char *LabelStmt::getName() const { return getDecl()->getIdentifier()->getNameStart(); } @@ -452,6 +444,14 @@ void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } +AddrLabelExpr *GCCAsmStmt::getLabelExpr(unsigned i) const { + return cast<AddrLabelExpr>(Exprs[i + NumInputs]); +} + +StringRef GCCAsmStmt::getLabelName(unsigned i) const { + return getLabelExpr(i)->getLabel()->getName(); +} + /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. StringRef GCCAsmStmt::getInputConstraint(unsigned i) const { @@ -464,13 +464,16 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C, Stmt **Exprs, unsigned NumOutputs, unsigned NumInputs, + unsigned NumLabels, StringLiteral **Clobbers, unsigned NumClobbers) { this->NumOutputs = NumOutputs; this->NumInputs = NumInputs; this->NumClobbers = NumClobbers; + this->NumLabels = NumLabels; + assert(!(NumOutputs && NumLabels) && "asm goto cannot have outputs"); - unsigned NumExprs = NumOutputs + NumInputs; + unsigned NumExprs = NumOutputs + NumInputs + NumLabels; C.Deallocate(this->Names); this->Names = new (C) IdentifierInfo*[NumExprs]; @@ -480,9 +483,10 @@ void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C, this->Exprs = new (C) Stmt*[NumExprs]; std::copy(Exprs, Exprs + NumExprs, this->Exprs); + unsigned NumConstraints = NumOutputs + NumInputs; C.Deallocate(this->Constraints); - this->Constraints = new (C) StringLiteral*[NumExprs]; - std::copy(Constraints, Constraints + NumExprs, this->Constraints); + this->Constraints = new (C) StringLiteral*[NumConstraints]; + std::copy(Constraints, Constraints + NumConstraints, this->Constraints); C.Deallocate(this->Clobbers); this->Clobbers = new (C) StringLiteral*[NumClobbers]; @@ -505,6 +509,10 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { if (getInputName(i) == SymbolicName) return getNumOutputs() + NumPlusOperands + i; + for (unsigned i = 0, e = getNumLabels(); i != e; ++i) + if (getLabelName(i) == SymbolicName) + return i + getNumInputs(); + // Not found. return -1; } @@ -622,8 +630,8 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, while (CurPtr != StrEnd && isDigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); - unsigned NumOperands = - getNumOutputs() + getNumPlusOperands() + getNumInputs(); + unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + + getNumInputs() + getNumLabels(); if (N >= NumOperands) { DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_operand_number; @@ -736,10 +744,12 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, unsigned numinputs, IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, - StringLiteral **clobbers, SourceLocation rparenloc) + StringLiteral **clobbers, unsigned numlabels, + SourceLocation rparenloc) : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, - numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { - unsigned NumExprs = NumOutputs + NumInputs; + numinputs, numclobbers), + RParenLoc(rparenloc), AsmStr(asmstr), NumLabels(numlabels) { + unsigned NumExprs = NumOutputs + NumInputs + NumLabels; Names = new (C) IdentifierInfo*[NumExprs]; std::copy(names, names + NumExprs, Names); @@ -747,8 +757,9 @@ GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, Exprs = new (C) Stmt*[NumExprs]; std::copy(exprs, exprs + NumExprs, Exprs); - Constraints = new (C) StringLiteral*[NumExprs]; - std::copy(constraints, constraints + NumExprs, Constraints); + unsigned NumConstraints = NumOutputs + NumInputs; + Constraints = new (C) StringLiteral*[NumConstraints]; + std::copy(constraints, constraints + NumConstraints, Constraints); Clobbers = new (C) StringLiteral*[NumClobbers]; std::copy(clobbers, clobbers + NumClobbers, Clobbers); @@ -1262,6 +1273,10 @@ Stmt::child_range CapturedStmt::children() { return child_range(getStoredStmts(), getStoredStmts() + NumCaptures); } +Stmt::const_child_range CapturedStmt::children() const { + return const_child_range(getStoredStmts(), getStoredStmts() + NumCaptures); +} + CapturedDecl *CapturedStmt::getCapturedDecl() { return CapDeclAndKind.getPointer(); } diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp index 12367f8fd54b3..060d090fc06ac 100644 --- a/lib/AST/StmtCXX.cpp +++ b/lib/AST/StmtCXX.cpp @@ -1,9 +1,8 @@ //===--- StmtCXX.cpp - Classes for representing C++ statements ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 00056e83af2c0..70c8dc94e2df6 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -1,9 +1,8 @@ //===- StmtIterator.cpp - Iterators for Statements ------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/StmtObjC.cpp b/lib/AST/StmtObjC.cpp index ed21e2d0d2b6b..3d586795517c4 100644 --- a/lib/AST/StmtObjC.cpp +++ b/lib/AST/StmtObjC.cpp @@ -1,9 +1,8 @@ //===--- StmtObjC.cpp - Classes for representing ObjC statements ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp index 85a2daa0801af..4e829897cebe6 100644 --- a/lib/AST/StmtOpenMP.cpp +++ b/lib/AST/StmtOpenMP.cpp @@ -1,9 +1,8 @@ //===--- StmtOpenMP.cpp - Classes for OpenMP directives -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,25 @@ void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) { std::copy(Clauses.begin(), Clauses.end(), getClauses().begin()); } +bool OMPExecutableDirective::isStandaloneDirective() const { + // Special case: 'omp target enter data', 'omp target exit data', + // 'omp target update' are stand-alone directives, but for implementation + // reasons they have empty synthetic structured block, to simplify codegen. + if (isa<OMPTargetEnterDataDirective>(this) || + isa<OMPTargetExitDataDirective>(this) || + isa<OMPTargetUpdateDirective>(this)) + return true; + return !hasAssociatedStmt() || !getAssociatedStmt(); +} + +const Stmt *OMPExecutableDirective::getStructuredBlock() const { + assert(!isStandaloneDirective() && + "Standalone Executable Directives don't have Structured Blocks."); + if (auto *LD = dyn_cast<OMPLoopDirective>(this)) + return LD->getBody(); + return getInnermostCapturedStmt()->getCapturedStmt(); +} + void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) { assert(A.size() == getCollapsedNumber() && "Number of loop counters is not the same as the collapsed number"); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index ae726e3871076..46802d765e1f0 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1,9 +1,8 @@ //===- StmtPrinter.cpp - Printing implementation for Stmt ASTs ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -37,6 +36,7 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/JsonSupport.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Lambda.h" #include "clang/Basic/OpenMPKinds.h" @@ -414,12 +414,15 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { if (Node->isVolatile()) OS << "volatile "; + if (Node->isAsmGoto()) + OS << "goto "; + OS << "("; VisitStringLiteral(Node->getAsmString()); // Outputs if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || - Node->getNumClobbers() != 0) + Node->getNumClobbers() != 0 || Node->getNumLabels() != 0) OS << " : "; for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { @@ -439,7 +442,8 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { } // Inputs - if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) + if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0 || + Node->getNumLabels() != 0) OS << " : "; for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { @@ -459,7 +463,7 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { } // Clobbers - if (Node->getNumClobbers() != 0) + if (Node->getNumClobbers() != 0 || Node->getNumLabels()) OS << " : "; for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { @@ -469,6 +473,16 @@ void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { VisitStringLiteral(Node->getClobberStringLiteral(i)); } + // Labels + if (Node->getNumLabels() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumLabels(); i != e; ++i) { + if (i != 0) + OS << ", "; + OS << Node->getLabelName(i); + } + OS << ");"; if (Policy.IncludeNewlines) OS << NL; } @@ -906,6 +920,10 @@ void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective( // Expr printing methods. //===----------------------------------------------------------------------===// +void StmtPrinter::VisitSourceLocExpr(SourceLocExpr *Node) { + OS << Node->getBuiltinStr() << "()"; +} + void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) { PrintExpr(Node->getSubExpr()); } @@ -1262,15 +1280,15 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { OS << "_Generic("; PrintExpr(Node->getControllingExpr()); - for (unsigned i = 0; i != Node->getNumAssocs(); ++i) { + for (const GenericSelectionExpr::Association &Assoc : Node->associations()) { OS << ", "; - QualType T = Node->getAssocType(i); + QualType T = Assoc.getType(); if (T.isNull()) OS << "default"; else T.print(OS, Policy); OS << ": "; - PrintExpr(Node->getAssocExpr(i)); + PrintExpr(Assoc.getAssociationExpr()); } OS << ")"; } @@ -1604,21 +1622,14 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { // C++ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { - const char *OpStrings[NUM_OVERLOADED_OPERATORS] = { - "", -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - OverloadedOperatorKind Kind = Node->getOperator(); if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { if (Node->getNumArgs() == 1) { - OS << OpStrings[Kind] << ' '; + OS << getOperatorSpelling(Kind) << ' '; PrintExpr(Node->getArg(0)); } else { PrintExpr(Node->getArg(0)); - OS << ' ' << OpStrings[Kind]; + OS << ' ' << getOperatorSpelling(Kind); } } else if (Kind == OO_Arrow) { PrintExpr(Node->getArg(0)); @@ -1638,11 +1649,11 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { PrintExpr(Node->getArg(1)); OS << ']'; } else if (Node->getNumArgs() == 1) { - OS << OpStrings[Kind] << ' '; + OS << getOperatorSpelling(Kind) << ' '; PrintExpr(Node->getArg(0)); } else if (Node->getNumArgs() == 2) { PrintExpr(Node->getArg(0)); - OS << ' ' << OpStrings[Kind] << ' '; + OS << ' ' << getOperatorSpelling(Kind) << ' '; PrintExpr(Node->getArg(1)); } else { llvm_unreachable("unknown overloaded operator"); @@ -1692,6 +1703,14 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) { VisitCXXNamedCastExpr(Node); } +void StmtPrinter::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *Node) { + OS << "__builtin_bit_cast("; + Node->getTypeInfoAsWritten()->getType().print(OS, Policy); + OS << ", "; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << "typeid("; if (Node->isTypeOperand()) { @@ -1896,13 +1915,22 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { llvm_unreachable("VLA type in explicit captures."); } + if (C->isPackExpansion()) + OS << "..."; + if (Node->isInitCapture(C)) PrintExpr(C->getCapturedVar()->getInit()); } OS << ']'; + if (!Node->getExplicitTemplateParameters().empty()) { + Node->getTemplateParameterList()->print( + OS, Node->getLambdaClass()->getASTContext(), + /*OmitTemplateKW*/true); + } + if (Node->hasExplicitParameters()) { - OS << " ("; + OS << '('; CXXMethodDecl *Method = Node->getCallOperator(); NeedComma = false; for (const auto *P : Method->parameters()) { @@ -1937,9 +1965,11 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { } // Print the body. - CompoundStmt *Body = Node->getBody(); OS << ' '; - PrintStmt(Body); + if (Policy.TerseOutput) + OS << "{}"; + else + PrintRawCompoundStmt(Node->getBody()); } void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) { @@ -1969,10 +1999,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { if (E->isParenTypeId()) OS << "("; std::string TypeS; - if (Expr *Size = E->getArraySize()) { + if (Optional<Expr *> Size = E->getArraySize()) { llvm::raw_string_ostream s(TypeS); s << '['; - Size->printPretty(s, Helper, Policy); + if (*Size) + (*Size)->printPretty(s, Helper, Policy); s << ']'; } E->getAllocatedType().print(OS, Policy, TypeS); @@ -2380,12 +2411,21 @@ void Stmt::dumpPretty(const ASTContext &Context) const { printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts())); } -void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper, +void Stmt::printPretty(raw_ostream &Out, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation, - StringRef NL, - const ASTContext *Context) const { - StmtPrinter P(OS, Helper, Policy, Indentation, NL, Context); - P.Visit(const_cast<Stmt*>(this)); + StringRef NL, const ASTContext *Context) const { + StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context); + P.Visit(const_cast<Stmt *>(this)); +} + +void Stmt::printJson(raw_ostream &Out, PrinterHelper *Helper, + const PrintingPolicy &Policy, bool AddQuotes) const { + std::string Buf; + llvm::raw_string_ostream TempOut(Buf); + + printPretty(TempOut, Helper, Policy); + + Out << JsonFormat(TempOut.str(), AddQuotes); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index ec4dac03d4974..f92c3dc60ba5c 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -1,9 +1,8 @@ //===---- StmtProfile.cpp - Profile implementation for Stmt ASTs ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -322,6 +321,9 @@ void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) { ID.AddInteger(S->getNumClobbers()); for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) VisitStringLiteral(S->getClobberStringLiteral(I)); + ID.AddInteger(S->getNumLabels()); + for (auto *L : S->labels()) + VisitDecl(L->getLabel()); } void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) { @@ -458,6 +460,11 @@ void OMPClauseProfiler::VisitOMPSimdlenClause(const OMPSimdlenClause *C) { Profiler->VisitStmt(C->getSimdlen()); } +void OMPClauseProfiler::VisitOMPAllocatorClause(const OMPAllocatorClause *C) { + if (C->getAllocator()) + Profiler->VisitStmt(C->getAllocator()); +} + void OMPClauseProfiler::VisitOMPCollapseClause(const OMPCollapseClause *C) { if (C->getNumForLoops()) Profiler->VisitStmt(C->getNumForLoops()); @@ -712,6 +719,11 @@ void OMPClauseProfiler::VisitOMPDeviceClause(const OMPDeviceClause *C) { void OMPClauseProfiler::VisitOMPMapClause(const OMPMapClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPAllocateClause(const OMPAllocateClause *C) { + if (Expr *Allocator = C->getAllocator()) + Profiler->VisitStmt(Allocator); + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) { VistOMPClauseWithPreInit(C); if (C->getNumTeams()) @@ -1260,13 +1272,14 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) { void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { VisitExpr(S); - for (unsigned i = 0; i != S->getNumAssocs(); ++i) { - QualType T = S->getAssocType(i); + for (const GenericSelectionExpr::ConstAssociation &Assoc : + S->associations()) { + QualType T = Assoc.getType(); if (T.isNull()) ID.AddPointer(nullptr); else VisitType(T); - VisitExpr(S->getAssocExpr(i)); + VisitExpr(Assoc.getAssociationExpr()); } } @@ -1556,6 +1569,11 @@ void StmtProfiler::VisitCXXConstCastExpr(const CXXConstCastExpr *S) { VisitCXXNamedCastExpr(S); } +void StmtProfiler::VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *S) { + VisitExpr(S); + VisitType(S->getTypeInfoAsWritten()->getType()); +} + void StmtProfiler::VisitUserDefinedLiteral(const UserDefinedLiteral *S) { VisitCallExpr(S); } @@ -1872,6 +1890,10 @@ void StmtProfiler::VisitTypoExpr(const TypoExpr *E) { VisitExpr(E); } +void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { + VisitExpr(E); +} + void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { VisitExpr(S); } diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp index 8be287e7cb217..4eb0da8a0e105 100644 --- a/lib/AST/StmtViz.cpp +++ b/lib/AST/StmtViz.cpp @@ -1,9 +1,8 @@ //===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index a78927d229b9f..cb4cbd2f76a12 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -1,9 +1,8 @@ //===- TemplateBase.cpp - Common template AST class implementation --------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 0a7a6bc3c6a7a..06e1dcec74492 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -1,9 +1,8 @@ //===- TemplateName.cpp - C++ Template Name Representation ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -67,6 +66,8 @@ TemplateName::TemplateName(void *Ptr) { TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {} TemplateName::TemplateName(OverloadedTemplateStorage *Storage) : Storage(Storage) {} +TemplateName::TemplateName(AssumedTemplateStorage *Storage) + : Storage(Storage) {} TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage) : Storage(Storage) {} TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage) @@ -88,6 +89,8 @@ TemplateName::NameKind TemplateName::getKind() const { = Storage.get<UncommonTemplateNameStorage*>(); if (uncommon->getAsOverloadedStorage()) return OverloadedTemplate; + if (uncommon->getAsAssumedTemplateName()) + return AssumedTemplate; if (uncommon->getAsSubstTemplateTemplateParm()) return SubstTemplateTemplateParm; return SubstTemplateTemplateParmPack; @@ -114,6 +117,14 @@ OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const { return nullptr; } +AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsAssumedTemplateName(); + + return nullptr; +} + SubstTemplateTemplateParmStorage * TemplateName::getAsSubstTemplateTemplateParm() const { if (UncommonTemplateNameStorage *uncommon = @@ -231,7 +242,9 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, } else if (SubstTemplateTemplateParmPackStorage *SubstPack = getAsSubstTemplateTemplateParmPack()) OS << *SubstPack->getParameterPack(); - else { + else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { + Assumed->getDeclName().print(OS, Policy); + } else { OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); (*OTS->begin())->printName(OS); } @@ -251,6 +264,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << NameStr; } +const PartialDiagnostic&clang::operator<<(const PartialDiagnostic &PD, + TemplateName N) { + std::string NameStr; + llvm::raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + OS << '\''; + N.print(OS, PrintingPolicy(LO)); + OS << '\''; + OS.flush(); + return PD << NameStr; +} + void TemplateName::dump(raw_ostream &OS) const { LangOptions LO; // FIXME! LO.CPlusPlus = true; diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp index b51a9006226ae..cba9091b10652 100644 --- a/lib/AST/TextNodeDumper.cpp +++ b/lib/AST/TextNodeDumper.cpp @@ -1,9 +1,8 @@ //===--- TextNodeDumper.cpp - Printing of AST nodes -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -122,6 +121,9 @@ void TextNodeDumper::Visit(const Stmt *Node) { dumpPointer(Node); dumpSourceRange(Node->getSourceRange()); + if (Node->isOMPStructuredBlock()) + OS << " openmp_structured_block"; + if (const auto *E = dyn_cast<Expr>(Node)) { dumpType(E->getType()); @@ -221,6 +223,7 @@ void TextNodeDumper::Visit(const Decl *D) { return; } + Context = &D->getASTContext(); { ColorScope Color(OS, ShowColors, DeclKindNameColor); OS << D->getDeclKindName() << "Decl"; @@ -253,9 +256,25 @@ void TextNodeDumper::Visit(const Decl *D) { if (D->isInvalidDecl()) OS << " invalid"; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (FD->isConstexpr()) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isConstexprSpecified()) OS << " constexpr"; + if (FD->isConsteval()) + OS << " consteval"; + } + + if (!isa<FunctionDecl>(*D)) { + const auto *MD = dyn_cast<ObjCMethodDecl>(D); + if (!MD || !MD->isThisDeclarationADefinition()) { + const auto *DC = dyn_cast<DeclContext>(D); + if (DC && DC->hasExternalLexicalStorage()) { + ColorScope Color(OS, ShowColors, UndeserializedColor); + OS << " <undeserialized declarations>"; + } + } + } + + ConstDeclVisitor<TextNodeDumper>::Visit(D); } void TextNodeDumper::Visit(const CXXCtorInitializer *Init) { @@ -302,6 +321,19 @@ void TextNodeDumper::Visit(const OMPClause *C) { OS << " <implicit>"; } +void TextNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) { + const TypeSourceInfo *TSI = A.getTypeSourceInfo(); + if (TSI) { + OS << "case "; + dumpType(TSI->getType()); + } else { + OS << "default"; + } + + if (A.isSelected()) + OS << " selected"; +} + void TextNodeDumper::dumpPointer(const void *Ptr) { ColorScope Color(OS, ShowColors, AddressColor); OS << ' ' << Ptr; @@ -416,12 +448,6 @@ void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { } } -void TextNodeDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { - OS << "(CXXTemporary"; - dumpPointer(Temporary); - OS << ")"; -} - void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { if (!D) return; @@ -658,6 +684,14 @@ void TextNodeDumper::VisitCaseStmt(const CaseStmt *Node) { OS << " gnu_range"; } +void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { + if (Node->getResultAPValueKind() != APValue::None) { + ColorScope Color(OS, ShowColors, ValueColor); + OS << " "; + Node->getAPValueResult().printPretty(OS, *Context, Node->getType()); + } +} + void TextNodeDumper::VisitCallExpr(const CallExpr *Node) { if (Node->usesADL()) OS << " adl"; @@ -687,6 +721,12 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { dumpBareDeclRef(Node->getFoundDecl()); OS << ")"; } + switch (Node->isNonOdrUse()) { + case NOUR_None: break; + case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break; + case NOUR_Constant: OS << " non_odr_use_constant"; break; + case NOUR_Discarded: OS << " non_odr_use_discarded"; break; + } } void TextNodeDumper::VisitUnresolvedLookupExpr( @@ -753,6 +793,11 @@ void TextNodeDumper::VisitInitListExpr(const InitListExpr *ILE) { } } +void TextNodeDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { + if (E->isResultDependent()) + OS << " result_dependent"; +} + void TextNodeDumper::VisitUnaryOperator(const UnaryOperator *Node) { OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; @@ -786,6 +831,12 @@ void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr( void TextNodeDumper::VisitMemberExpr(const MemberExpr *Node) { OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl(); dumpPointer(Node->getMemberDecl()); + switch (Node->isNonOdrUse()) { + case NOUR_None: break; + case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break; + case NOUR_Constant: OS << " non_odr_use_constant"; break; + case NOUR_Discarded: OS << " non_odr_use_discarded"; break; + } } void TextNodeDumper::VisitExtVectorElementExpr( @@ -824,6 +875,8 @@ void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { } void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { + if (Node->isImplicit()) + OS << " implicit"; OS << " this"; } @@ -855,8 +908,9 @@ void TextNodeDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) { void TextNodeDumper::VisitCXXBindTemporaryExpr( const CXXBindTemporaryExpr *Node) { - OS << " "; - dumpCXXTemporary(Node->getTemporary()); + OS << " (CXXTemporary"; + dumpPointer(Node); + OS << ")"; } void TextNodeDumper::VisitCXXNewExpr(const CXXNewExpr *Node) { @@ -1096,6 +1150,8 @@ void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) { OS << " volatile"; if (T->isRestrict()) OS << " restrict"; + if (T->getExtProtoInfo().Variadic) + OS << " variadic"; switch (EPI.RefQualifier) { case RQ_None: break; @@ -1166,3 +1222,721 @@ void TextNodeDumper::VisitPackExpansionType(const PackExpansionType *T) { if (auto N = T->getNumExpansions()) OS << " expansions " << *N; } + +void TextNodeDumper::VisitLabelDecl(const LabelDecl *D) { dumpName(D); } + +void TextNodeDumper::VisitTypedefDecl(const TypedefDecl *D) { + dumpName(D); + dumpType(D->getUnderlyingType()); + if (D->isModulePrivate()) + OS << " __module_private__"; +} + +void TextNodeDumper::VisitEnumDecl(const EnumDecl *D) { + if (D->isScoped()) { + if (D->isScopedUsingClassTag()) + OS << " class"; + else + OS << " struct"; + } + dumpName(D); + if (D->isModulePrivate()) + OS << " __module_private__"; + if (D->isFixed()) + dumpType(D->getIntegerType()); +} + +void TextNodeDumper::VisitRecordDecl(const RecordDecl *D) { + OS << ' ' << D->getKindName(); + dumpName(D); + if (D->isModulePrivate()) + OS << " __module_private__"; + if (D->isCompleteDefinition()) + OS << " definition"; +} + +void TextNodeDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { + dumpName(D); + dumpType(D->getType()); +} + +void TextNodeDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { + dumpName(D); + dumpType(D->getType()); + + for (const auto *Child : D->chain()) + dumpDeclRef(Child); +} + +void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { + dumpName(D); + dumpType(D->getType()); + + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); + if (D->isInlineSpecified()) + OS << " inline"; + if (D->isVirtualAsWritten()) + OS << " virtual"; + if (D->isModulePrivate()) + OS << " __module_private__"; + + if (D->isPure()) + OS << " pure"; + if (D->isDefaulted()) { + OS << " default"; + if (D->isDeleted()) + OS << "_delete"; + } + if (D->isDeletedAsWritten()) + OS << " delete"; + if (D->isTrivial()) + OS << " trivial"; + + if (const auto *FPT = D->getType()->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + switch (EPI.ExceptionSpec.Type) { + default: + break; + case EST_Unevaluated: + OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl; + break; + case EST_Uninstantiated: + OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate; + break; + } + } + + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->size_overridden_methods() != 0) { + auto dumpOverride = [=](const CXXMethodDecl *D) { + SplitQualType T_split = D->getType().split(); + OS << D << " " << D->getParent()->getName() + << "::" << D->getNameAsString() << " '" + << QualType::getAsString(T_split, PrintPolicy) << "'"; + }; + + AddChild([=] { + auto Overrides = MD->overridden_methods(); + OS << "Overrides: [ "; + dumpOverride(*Overrides.begin()); + for (const auto *Override : + llvm::make_range(Overrides.begin() + 1, Overrides.end())) { + OS << ", "; + dumpOverride(Override); + } + OS << " ]"; + }); + } + } + + // Since NumParams comes from the FunctionProtoType of the FunctionDecl and + // the Params are set later, it is possible for a dump during debugging to + // encounter a FunctionDecl that has been created but hasn't been assigned + // ParmVarDecls yet. + if (!D->param_empty() && !D->param_begin()) + OS << " <<<NULL params x " << D->getNumParams() << ">>>"; +} + +void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (D->isMutable()) + OS << " mutable"; + if (D->isModulePrivate()) + OS << " __module_private__"; +} + +void TextNodeDumper::VisitVarDecl(const VarDecl *D) { + dumpName(D); + dumpType(D->getType()); + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); + switch (D->getTLSKind()) { + case VarDecl::TLS_None: + break; + case VarDecl::TLS_Static: + OS << " tls"; + break; + case VarDecl::TLS_Dynamic: + OS << " tls_dynamic"; + break; + } + if (D->isModulePrivate()) + OS << " __module_private__"; + if (D->isNRVOVariable()) + OS << " nrvo"; + if (D->isInline()) + OS << " inline"; + if (D->isConstexpr()) + OS << " constexpr"; + if (D->hasInit()) { + switch (D->getInitStyle()) { + case VarDecl::CInit: + OS << " cinit"; + break; + case VarDecl::CallInit: + OS << " callinit"; + break; + case VarDecl::ListInit: + OS << " listinit"; + break; + } + } + if (D->isParameterPack()) + OS << " pack"; +} + +void TextNodeDumper::VisitBindingDecl(const BindingDecl *D) { + dumpName(D); + dumpType(D->getType()); +} + +void TextNodeDumper::VisitCapturedDecl(const CapturedDecl *D) { + if (D->isNothrow()) + OS << " nothrow"; +} + +void TextNodeDumper::VisitImportDecl(const ImportDecl *D) { + OS << ' ' << D->getImportedModule()->getFullModuleName(); + + for (Decl *InitD : + D->getASTContext().getModuleInitializers(D->getImportedModule())) + dumpDeclRef(InitD, "initializer"); +} + +void TextNodeDumper::VisitPragmaCommentDecl(const PragmaCommentDecl *D) { + OS << ' '; + switch (D->getCommentKind()) { + case PCK_Unknown: + llvm_unreachable("unexpected pragma comment kind"); + case PCK_Compiler: + OS << "compiler"; + break; + case PCK_ExeStr: + OS << "exestr"; + break; + case PCK_Lib: + OS << "lib"; + break; + case PCK_Linker: + OS << "linker"; + break; + case PCK_User: + OS << "user"; + break; + } + StringRef Arg = D->getArg(); + if (!Arg.empty()) + OS << " \"" << Arg << "\""; +} + +void TextNodeDumper::VisitPragmaDetectMismatchDecl( + const PragmaDetectMismatchDecl *D) { + OS << " \"" << D->getName() << "\" \"" << D->getValue() << "\""; +} + +void TextNodeDumper::VisitOMPExecutableDirective( + const OMPExecutableDirective *D) { + if (D->isStandaloneDirective()) + OS << " openmp_standalone_directive"; +} + +void TextNodeDumper::VisitOMPDeclareReductionDecl( + const OMPDeclareReductionDecl *D) { + dumpName(D); + dumpType(D->getType()); + OS << " combiner"; + dumpPointer(D->getCombiner()); + if (const auto *Initializer = D->getInitializer()) { + OS << " initializer"; + dumpPointer(Initializer); + switch (D->getInitializerKind()) { + case OMPDeclareReductionDecl::DirectInit: + OS << " omp_priv = "; + break; + case OMPDeclareReductionDecl::CopyInit: + OS << " omp_priv ()"; + break; + case OMPDeclareReductionDecl::CallInit: + break; + } + } +} + +void TextNodeDumper::VisitOMPRequiresDecl(const OMPRequiresDecl *D) { + for (const auto *C : D->clauselists()) { + AddChild([=] { + if (!C) { + ColorScope Color(OS, ShowColors, NullColor); + OS << "<<<NULL>>> OMPClause"; + return; + } + { + ColorScope Color(OS, ShowColors, AttrColor); + StringRef ClauseName(getOpenMPClauseName(C->getClauseKind())); + OS << "OMP" << ClauseName.substr(/*Start=*/0, /*N=*/1).upper() + << ClauseName.drop_front() << "Clause"; + } + dumpPointer(C); + dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc())); + }); + } +} + +void TextNodeDumper::VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D) { + dumpName(D); + dumpType(D->getType()); +} + +void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) { + dumpName(D); + if (D->isInline()) + OS << " inline"; + if (!D->isOriginalNamespace()) + dumpDeclRef(D->getOriginalNamespace(), "original"); +} + +void TextNodeDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { + OS << ' '; + dumpBareDeclRef(D->getNominatedNamespace()); +} + +void TextNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) { + dumpName(D); + dumpDeclRef(D->getAliasedNamespace()); +} + +void TextNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) { + dumpName(D); + dumpType(D->getUnderlyingType()); +} + +void TextNodeDumper::VisitTypeAliasTemplateDecl( + const TypeAliasTemplateDecl *D) { + dumpName(D); +} + +void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { + VisitRecordDecl(D); + if (!D->isCompleteDefinition()) + return; + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "DefinitionData"; + } +#define FLAG(fn, name) \ + if (D->fn()) \ + OS << " " #name; + FLAG(isParsingBaseSpecifiers, parsing_base_specifiers); + + FLAG(isGenericLambda, generic); + FLAG(isLambda, lambda); + + FLAG(canPassInRegisters, pass_in_registers); + FLAG(isEmpty, empty); + FLAG(isAggregate, aggregate); + FLAG(isStandardLayout, standard_layout); + FLAG(isTriviallyCopyable, trivially_copyable); + FLAG(isPOD, pod); + FLAG(isTrivial, trivial); + FLAG(isPolymorphic, polymorphic); + FLAG(isAbstract, abstract); + FLAG(isLiteral, literal); + + FLAG(hasUserDeclaredConstructor, has_user_declared_ctor); + FLAG(hasConstexprNonCopyMoveConstructor, has_constexpr_non_copy_move_ctor); + FLAG(hasMutableFields, has_mutable_fields); + FLAG(hasVariantMembers, has_variant_members); + FLAG(allowConstDefaultInit, can_const_default_init); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "DefaultConstructor"; + } + FLAG(hasDefaultConstructor, exists); + FLAG(hasTrivialDefaultConstructor, trivial); + FLAG(hasNonTrivialDefaultConstructor, non_trivial); + FLAG(hasUserProvidedDefaultConstructor, user_provided); + FLAG(hasConstexprDefaultConstructor, constexpr); + FLAG(needsImplicitDefaultConstructor, needs_implicit); + FLAG(defaultedDefaultConstructorIsConstexpr, defaulted_is_constexpr); + }); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "CopyConstructor"; + } + FLAG(hasSimpleCopyConstructor, simple); + FLAG(hasTrivialCopyConstructor, trivial); + FLAG(hasNonTrivialCopyConstructor, non_trivial); + FLAG(hasUserDeclaredCopyConstructor, user_declared); + FLAG(hasCopyConstructorWithConstParam, has_const_param); + FLAG(needsImplicitCopyConstructor, needs_implicit); + FLAG(needsOverloadResolutionForCopyConstructor, + needs_overload_resolution); + if (!D->needsOverloadResolutionForCopyConstructor()) + FLAG(defaultedCopyConstructorIsDeleted, defaulted_is_deleted); + FLAG(implicitCopyConstructorHasConstParam, implicit_has_const_param); + }); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "MoveConstructor"; + } + FLAG(hasMoveConstructor, exists); + FLAG(hasSimpleMoveConstructor, simple); + FLAG(hasTrivialMoveConstructor, trivial); + FLAG(hasNonTrivialMoveConstructor, non_trivial); + FLAG(hasUserDeclaredMoveConstructor, user_declared); + FLAG(needsImplicitMoveConstructor, needs_implicit); + FLAG(needsOverloadResolutionForMoveConstructor, + needs_overload_resolution); + if (!D->needsOverloadResolutionForMoveConstructor()) + FLAG(defaultedMoveConstructorIsDeleted, defaulted_is_deleted); + }); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "CopyAssignment"; + } + FLAG(hasTrivialCopyAssignment, trivial); + FLAG(hasNonTrivialCopyAssignment, non_trivial); + FLAG(hasCopyAssignmentWithConstParam, has_const_param); + FLAG(hasUserDeclaredCopyAssignment, user_declared); + FLAG(needsImplicitCopyAssignment, needs_implicit); + FLAG(needsOverloadResolutionForCopyAssignment, needs_overload_resolution); + FLAG(implicitCopyAssignmentHasConstParam, implicit_has_const_param); + }); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "MoveAssignment"; + } + FLAG(hasMoveAssignment, exists); + FLAG(hasSimpleMoveAssignment, simple); + FLAG(hasTrivialMoveAssignment, trivial); + FLAG(hasNonTrivialMoveAssignment, non_trivial); + FLAG(hasUserDeclaredMoveAssignment, user_declared); + FLAG(needsImplicitMoveAssignment, needs_implicit); + FLAG(needsOverloadResolutionForMoveAssignment, needs_overload_resolution); + }); + + AddChild([=] { + { + ColorScope Color(OS, ShowColors, DeclKindNameColor); + OS << "Destructor"; + } + FLAG(hasSimpleDestructor, simple); + FLAG(hasIrrelevantDestructor, irrelevant); + FLAG(hasTrivialDestructor, trivial); + FLAG(hasNonTrivialDestructor, non_trivial); + FLAG(hasUserDeclaredDestructor, user_declared); + FLAG(needsImplicitDestructor, needs_implicit); + FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution); + if (!D->needsOverloadResolutionForDestructor()) + FLAG(defaultedDestructorIsDeleted, defaulted_is_deleted); + }); + }); + + for (const auto &I : D->bases()) { + AddChild([=] { + if (I.isVirtual()) + OS << "virtual "; + dumpAccessSpecifier(I.getAccessSpecifier()); + dumpType(I.getType()); + if (I.isPackExpansion()) + OS << "..."; + }); + } +} + +void TextNodeDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { + dumpName(D); +} + +void TextNodeDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) { + dumpName(D); +} + +void TextNodeDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { + dumpName(D); +} + +void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { + dumpName(D); +} + +void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { + if (D->wasDeclaredWithTypename()) + OS << " typename"; + else + OS << " class"; + OS << " depth " << D->getDepth() << " index " << D->getIndex(); + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); +} + +void TextNodeDumper::VisitNonTypeTemplateParmDecl( + const NonTypeTemplateParmDecl *D) { + dumpType(D->getType()); + OS << " depth " << D->getDepth() << " index " << D->getIndex(); + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); +} + +void TextNodeDumper::VisitTemplateTemplateParmDecl( + const TemplateTemplateParmDecl *D) { + OS << " depth " << D->getDepth() << " index " << D->getIndex(); + if (D->isParameterPack()) + OS << " ..."; + dumpName(D); +} + +void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) { + OS << ' '; + if (D->getQualifier()) + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); +} + +void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( + const UnresolvedUsingTypenameDecl *D) { + OS << ' '; + if (D->getQualifier()) + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); +} + +void TextNodeDumper::VisitUnresolvedUsingValueDecl( + const UnresolvedUsingValueDecl *D) { + OS << ' '; + if (D->getQualifier()) + D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + OS << D->getNameAsString(); + dumpType(D->getType()); +} + +void TextNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) { + OS << ' '; + dumpBareDeclRef(D->getTargetDecl()); +} + +void TextNodeDumper::VisitConstructorUsingShadowDecl( + const ConstructorUsingShadowDecl *D) { + if (D->constructsVirtualBase()) + OS << " virtual"; + + AddChild([=] { + OS << "target "; + dumpBareDeclRef(D->getTargetDecl()); + }); + + AddChild([=] { + OS << "nominated "; + dumpBareDeclRef(D->getNominatedBaseClass()); + OS << ' '; + dumpBareDeclRef(D->getNominatedBaseClassShadowDecl()); + }); + + AddChild([=] { + OS << "constructed "; + dumpBareDeclRef(D->getConstructedBaseClass()); + OS << ' '; + dumpBareDeclRef(D->getConstructedBaseClassShadowDecl()); + }); +} + +void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { + switch (D->getLanguage()) { + case LinkageSpecDecl::lang_c: + OS << " C"; + break; + case LinkageSpecDecl::lang_cxx: + OS << " C++"; + break; + } +} + +void TextNodeDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { + OS << ' '; + dumpAccessSpecifier(D->getAccess()); +} + +void TextNodeDumper::VisitFriendDecl(const FriendDecl *D) { + if (TypeSourceInfo *T = D->getFriendType()) + dumpType(T->getType()); +} + +void TextNodeDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (D->getSynthesize()) + OS << " synthesize"; + + switch (D->getAccessControl()) { + case ObjCIvarDecl::None: + OS << " none"; + break; + case ObjCIvarDecl::Private: + OS << " private"; + break; + case ObjCIvarDecl::Protected: + OS << " protected"; + break; + case ObjCIvarDecl::Public: + OS << " public"; + break; + case ObjCIvarDecl::Package: + OS << " package"; + break; + } +} + +void TextNodeDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { + if (D->isInstanceMethod()) + OS << " -"; + else + OS << " +"; + dumpName(D); + dumpType(D->getReturnType()); + + if (D->isVariadic()) + OS << " variadic"; +} + +void TextNodeDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) { + dumpName(D); + switch (D->getVariance()) { + case ObjCTypeParamVariance::Invariant: + break; + + case ObjCTypeParamVariance::Covariant: + OS << " covariant"; + break; + + case ObjCTypeParamVariance::Contravariant: + OS << " contravariant"; + break; + } + + if (D->hasExplicitBound()) + OS << " bounded"; + dumpType(D->getUnderlyingType()); +} + +void TextNodeDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + dumpName(D); + dumpDeclRef(D->getClassInterface()); + dumpDeclRef(D->getImplementation()); + for (const auto *P : D->protocols()) + dumpDeclRef(P); +} + +void TextNodeDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + dumpName(D); + dumpDeclRef(D->getClassInterface()); + dumpDeclRef(D->getCategoryDecl()); +} + +void TextNodeDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + dumpName(D); + + for (const auto *Child : D->protocols()) + dumpDeclRef(Child); +} + +void TextNodeDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + dumpName(D); + dumpDeclRef(D->getSuperClass(), "super"); + + dumpDeclRef(D->getImplementation()); + for (const auto *Child : D->protocols()) + dumpDeclRef(Child); +} + +void TextNodeDumper::VisitObjCImplementationDecl( + const ObjCImplementationDecl *D) { + dumpName(D); + dumpDeclRef(D->getSuperClass(), "super"); + dumpDeclRef(D->getClassInterface()); +} + +void TextNodeDumper::VisitObjCCompatibleAliasDecl( + const ObjCCompatibleAliasDecl *D) { + dumpName(D); + dumpDeclRef(D->getClassInterface()); +} + +void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + dumpName(D); + dumpType(D->getType()); + + if (D->getPropertyImplementation() == ObjCPropertyDecl::Required) + OS << " required"; + else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional) + OS << " optional"; + + ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes(); + if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) { + if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly) + OS << " readonly"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_assign) + OS << " assign"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite) + OS << " readwrite"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_retain) + OS << " retain"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_copy) + OS << " copy"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) + OS << " nonatomic"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic) + OS << " atomic"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_weak) + OS << " weak"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_strong) + OS << " strong"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) + OS << " unsafe_unretained"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_class) + OS << " class"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) + dumpDeclRef(D->getGetterMethodDecl(), "getter"); + if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) + dumpDeclRef(D->getSetterMethodDecl(), "setter"); + } +} + +void TextNodeDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + dumpName(D->getPropertyDecl()); + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) + OS << " synthesize"; + else + OS << " dynamic"; + dumpDeclRef(D->getPropertyDecl()); + dumpDeclRef(D->getPropertyIvarDecl()); +} + +void TextNodeDumper::VisitBlockDecl(const BlockDecl *D) { + if (D->isVariadic()) + OS << " variadic"; + + if (D->capturesCXXThis()) + OS << " captures_this"; +} + +void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) { + dumpName(D); +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0dbc88c04521d..ed75a0b5bcd85 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1,9 +1,8 @@ //===- Type.cpp - Type representation and manipulation --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -723,25 +723,30 @@ const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( return ctx.getObjCObjectPointerType(obj)->castAs<ObjCObjectPointerType>(); } -template<typename F> -static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f); - namespace { -/// Visitor used by simpleTransform() to perform the transformation. -template<typename F> -struct SimpleTransformVisitor - : public TypeVisitor<SimpleTransformVisitor<F>, QualType> { +/// Visitor used to perform a simple type transformation that does not change +/// the semantics of the type. +template <typename Derived> +struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> { ASTContext &Ctx; - F &&TheFunc; QualType recurse(QualType type) { - return simpleTransform(Ctx, type, std::move(TheFunc)); + // Split out the qualifiers from the type. + SplitQualType splitType = type.split(); + + // Visit the type itself. + QualType result = static_cast<Derived *>(this)->Visit(splitType.Ty); + if (result.isNull()) + return result; + + // Reconstruct the transformed type by applying the local qualifiers + // from the split type. + return Ctx.getQualifiedType(result, splitType.Quals); } public: - SimpleTransformVisitor(ASTContext &ctx, F &&f) - : Ctx(ctx), TheFunc(std::move(f)) {} + explicit SimpleTransformVisitor(ASTContext &ctx) : Ctx(ctx) {} // None of the clients of this transformation can occur where // there are dependent types, so skip dependent types. @@ -752,6 +757,17 @@ public: #define TRIVIAL_TYPE_CLASS(Class) \ QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } +#define SUGARED_TYPE_CLASS(Class) \ + QualType Visit##Class##Type(const Class##Type *T) { \ + if (!T->isSugared()) \ + return QualType(T, 0); \ + QualType desugaredType = recurse(T->desugar()); \ + if (desugaredType.isNull()) \ + return {}; \ + if (desugaredType.getAsOpaquePtr() == T->desugar().getAsOpaquePtr()) \ + return QualType(T, 0); \ + return desugaredType; \ + } TRIVIAL_TYPE_CLASS(Builtin) @@ -955,8 +971,9 @@ public: return Ctx.getParenType(innerType); } - TRIVIAL_TYPE_CLASS(Typedef) - TRIVIAL_TYPE_CLASS(ObjCTypeParam) + SUGARED_TYPE_CLASS(Typedef) + SUGARED_TYPE_CLASS(ObjCTypeParam) + SUGARED_TYPE_CLASS(MacroQualified) QualType VisitAdjustedType(const AdjustedType *T) { QualType originalType = recurse(T->getOriginalType()); @@ -987,15 +1004,15 @@ public: return Ctx.getDecayedType(originalType); } - TRIVIAL_TYPE_CLASS(TypeOfExpr) - TRIVIAL_TYPE_CLASS(TypeOf) - TRIVIAL_TYPE_CLASS(Decltype) - TRIVIAL_TYPE_CLASS(UnaryTransform) + SUGARED_TYPE_CLASS(TypeOfExpr) + SUGARED_TYPE_CLASS(TypeOf) + SUGARED_TYPE_CLASS(Decltype) + SUGARED_TYPE_CLASS(UnaryTransform) TRIVIAL_TYPE_CLASS(Record) TRIVIAL_TYPE_CLASS(Enum) // FIXME: Non-trivial to implement, but important for C++ - TRIVIAL_TYPE_CLASS(Elaborated) + SUGARED_TYPE_CLASS(Elaborated) QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); @@ -1030,7 +1047,7 @@ public: } // FIXME: Non-trivial to implement, but important for C++ - TRIVIAL_TYPE_CLASS(TemplateSpecialization) + SUGARED_TYPE_CLASS(TemplateSpecialization) QualType VisitAutoType(const AutoType *T) { if (!T->isDeduced()) @@ -1049,7 +1066,7 @@ public: } // FIXME: Non-trivial to implement, but important for C++ - TRIVIAL_TYPE_CLASS(PackExpansion) + SUGARED_TYPE_CLASS(PackExpansion) QualType VisitObjCObjectType(const ObjCObjectType *T) { QualType baseType = recurse(T->getBaseType()); @@ -1107,222 +1124,245 @@ public: } #undef TRIVIAL_TYPE_CLASS +#undef SUGARED_TYPE_CLASS }; -} // namespace - -/// Perform a simple type transformation that does not change the -/// semantics of the type. -template<typename F> -static QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { - // Transform the type. If it changed, return the transformed result. - QualType transformed = f(type); - if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr()) - return transformed; - - // Split out the qualifiers from the type. - SplitQualType splitType = type.split(); - - // Visit the type itself. - SimpleTransformVisitor<F> visitor(ctx, std::forward<F>(f)); - QualType result = visitor.Visit(splitType.Ty); - if (result.isNull()) - return result; +struct SubstObjCTypeArgsVisitor + : public SimpleTransformVisitor<SubstObjCTypeArgsVisitor> { + using BaseType = SimpleTransformVisitor<SubstObjCTypeArgsVisitor>; - // Reconstruct the transformed type by applying the local qualifiers - // from the split type. - return ctx.getQualifiedType(result, splitType.Quals); -} + ArrayRef<QualType> TypeArgs; + ObjCSubstitutionContext SubstContext; -/// Substitute the given type arguments for Objective-C type -/// parameters within the given type, recursively. -QualType QualType::substObjCTypeArgs( - ASTContext &ctx, - ArrayRef<QualType> typeArgs, - ObjCSubstitutionContext context) const { - return simpleTransform(ctx, *this, - [&](QualType type) -> QualType { - SplitQualType splitType = type.split(); + SubstObjCTypeArgsVisitor(ASTContext &ctx, ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) + : BaseType(ctx), TypeArgs(typeArgs), SubstContext(context) {} + QualType VisitObjCTypeParamType(const ObjCTypeParamType *OTPTy) { // Replace an Objective-C type parameter reference with the corresponding // type argument. - if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) { - ObjCTypeParamDecl *typeParam = OTPTy->getDecl(); - // If we have type arguments, use them. - if (!typeArgs.empty()) { - QualType argType = typeArgs[typeParam->getIndex()]; - if (OTPTy->qual_empty()) - return ctx.getQualifiedType(argType, splitType.Quals); - - // Apply protocol lists if exists. - bool hasError; - SmallVector<ObjCProtocolDecl*, 8> protocolsVec; - protocolsVec.append(OTPTy->qual_begin(), - OTPTy->qual_end()); - ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec; - QualType resultTy = ctx.applyObjCProtocolQualifiers(argType, - protocolsToApply, hasError, true/*allowOnPointerType*/); - - return ctx.getQualifiedType(resultTy, splitType.Quals); - } + ObjCTypeParamDecl *typeParam = OTPTy->getDecl(); + // If we have type arguments, use them. + if (!TypeArgs.empty()) { + QualType argType = TypeArgs[typeParam->getIndex()]; + if (OTPTy->qual_empty()) + return argType; + + // Apply protocol lists if exists. + bool hasError; + SmallVector<ObjCProtocolDecl *, 8> protocolsVec; + protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end()); + ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec; + return Ctx.applyObjCProtocolQualifiers( + argType, protocolsToApply, hasError, true/*allowOnPointerType*/); + } - switch (context) { - case ObjCSubstitutionContext::Ordinary: - case ObjCSubstitutionContext::Parameter: - case ObjCSubstitutionContext::Superclass: - // Substitute the bound. - return ctx.getQualifiedType(typeParam->getUnderlyingType(), - splitType.Quals); - - case ObjCSubstitutionContext::Result: - case ObjCSubstitutionContext::Property: { - // Substitute the __kindof form of the underlying type. - const auto *objPtr = typeParam->getUnderlyingType() - ->castAs<ObjCObjectPointerType>(); - - // __kindof types, id, and Class don't need an additional - // __kindof. - if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) - return ctx.getQualifiedType(typeParam->getUnderlyingType(), - splitType.Quals); - - // Add __kindof. - const auto *obj = objPtr->getObjectType(); - QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(), - obj->getTypeArgsAsWritten(), - obj->getProtocols(), - /*isKindOf=*/true); - - // Rebuild object pointer type. - resultTy = ctx.getObjCObjectPointerType(resultTy); - return ctx.getQualifiedType(resultTy, splitType.Quals); - } - } + switch (SubstContext) { + case ObjCSubstitutionContext::Ordinary: + case ObjCSubstitutionContext::Parameter: + case ObjCSubstitutionContext::Superclass: + // Substitute the bound. + return typeParam->getUnderlyingType(); + + case ObjCSubstitutionContext::Result: + case ObjCSubstitutionContext::Property: { + // Substitute the __kindof form of the underlying type. + const auto *objPtr = + typeParam->getUnderlyingType()->castAs<ObjCObjectPointerType>(); + + // __kindof types, id, and Class don't need an additional + // __kindof. + if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) + return typeParam->getUnderlyingType(); + + // Add __kindof. + const auto *obj = objPtr->getObjectType(); + QualType resultTy = Ctx.getObjCObjectType( + obj->getBaseType(), obj->getTypeArgsAsWritten(), obj->getProtocols(), + /*isKindOf=*/true); + + // Rebuild object pointer type. + return Ctx.getObjCObjectPointerType(resultTy); + } + } + llvm_unreachable("Unexpected ObjCSubstitutionContext!"); + } + + QualType VisitFunctionType(const FunctionType *funcType) { + // If we have a function type, update the substitution context + // appropriately. + + //Substitute result type. + QualType returnType = funcType->getReturnType().substObjCTypeArgs( + Ctx, TypeArgs, ObjCSubstitutionContext::Result); + if (returnType.isNull()) + return {}; + + // Handle non-prototyped functions, which only substitute into the result + // type. + if (isa<FunctionNoProtoType>(funcType)) { + // If the return type was unchanged, do nothing. + if (returnType.getAsOpaquePtr() == + funcType->getReturnType().getAsOpaquePtr()) + return BaseType::VisitFunctionType(funcType); + + // Otherwise, build a new type. + return Ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); } - // If we have a function type, update the context appropriately. - if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) { - // Substitute result type. - QualType returnType = funcType->getReturnType().substObjCTypeArgs( - ctx, - typeArgs, - ObjCSubstitutionContext::Result); - if (returnType.isNull()) + const auto *funcProtoType = cast<FunctionProtoType>(funcType); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : funcProtoType->getParamTypes()) { + QualType newParamType = paramType.substObjCTypeArgs( + Ctx, TypeArgs, ObjCSubstitutionContext::Parameter); + if (newParamType.isNull()) return {}; - // Handle non-prototyped functions, which only substitute into the result - // type. - if (isa<FunctionNoProtoType>(funcType)) { - // If the return type was unchanged, do nothing. - if (returnType.getAsOpaquePtr() - == funcType->getReturnType().getAsOpaquePtr()) - return type; + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; - // Otherwise, build a new type. - return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); - } + paramTypes.push_back(newParamType); + } - const auto *funcProtoType = cast<FunctionProtoType>(funcType); - - // Transform parameter types. - SmallVector<QualType, 4> paramTypes; - bool paramChanged = false; - for (auto paramType : funcProtoType->getParamTypes()) { - QualType newParamType = paramType.substObjCTypeArgs( - ctx, - typeArgs, - ObjCSubstitutionContext::Parameter); - if (newParamType.isNull()) + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = exceptionType.substObjCTypeArgs( + Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary); + if (newExceptionType.isNull()) return {}; - if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) - paramChanged = true; + if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; - paramTypes.push_back(newParamType); + exceptionTypes.push_back(newExceptionType); } - // Transform extended info. - FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); - bool exceptionChanged = false; - if (info.ExceptionSpec.Type == EST_Dynamic) { - SmallVector<QualType, 4> exceptionTypes; - for (auto exceptionType : info.ExceptionSpec.Exceptions) { - QualType newExceptionType = exceptionType.substObjCTypeArgs( - ctx, - typeArgs, - ObjCSubstitutionContext::Ordinary); - if (newExceptionType.isNull()) - return {}; - - if (newExceptionType.getAsOpaquePtr() - != exceptionType.getAsOpaquePtr()) - exceptionChanged = true; - - exceptionTypes.push_back(newExceptionType); - } - - if (exceptionChanged) { - info.ExceptionSpec.Exceptions = - llvm::makeArrayRef(exceptionTypes).copy(ctx); - } + if (exceptionChanged) { + info.ExceptionSpec.Exceptions = + llvm::makeArrayRef(exceptionTypes).copy(Ctx); } + } - if (returnType.getAsOpaquePtr() - == funcProtoType->getReturnType().getAsOpaquePtr() && - !paramChanged && !exceptionChanged) - return type; + if (returnType.getAsOpaquePtr() == + funcProtoType->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return BaseType::VisitFunctionType(funcType); - return ctx.getFunctionType(returnType, paramTypes, info); - } + return Ctx.getFunctionType(returnType, paramTypes, info); + } + QualType VisitObjCObjectType(const ObjCObjectType *objcObjectType) { // Substitute into the type arguments of a specialized Objective-C object // type. - if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) { - if (objcObjectType->isSpecializedAsWritten()) { - SmallVector<QualType, 4> newTypeArgs; - bool anyChanged = false; - for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { - QualType newTypeArg = typeArg.substObjCTypeArgs( - ctx, typeArgs, - ObjCSubstitutionContext::Ordinary); - if (newTypeArg.isNull()) - return {}; - - if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { - // If we're substituting based on an unspecialized context type, - // produce an unspecialized type. - ArrayRef<ObjCProtocolDecl *> protocols( - objcObjectType->qual_begin(), - objcObjectType->getNumProtocols()); - if (typeArgs.empty() && - context != ObjCSubstitutionContext::Superclass) { - return ctx.getObjCObjectType( - objcObjectType->getBaseType(), {}, - protocols, - objcObjectType->isKindOfTypeAsWritten()); - } - - anyChanged = true; + if (objcObjectType->isSpecializedAsWritten()) { + SmallVector<QualType, 4> newTypeArgs; + bool anyChanged = false; + for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { + QualType newTypeArg = typeArg.substObjCTypeArgs( + Ctx, TypeArgs, ObjCSubstitutionContext::Ordinary); + if (newTypeArg.isNull()) + return {}; + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { + // If we're substituting based on an unspecialized context type, + // produce an unspecialized type. + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), objcObjectType->getNumProtocols()); + if (TypeArgs.empty() && + SubstContext != ObjCSubstitutionContext::Superclass) { + return Ctx.getObjCObjectType( + objcObjectType->getBaseType(), {}, protocols, + objcObjectType->isKindOfTypeAsWritten()); } - newTypeArgs.push_back(newTypeArg); + anyChanged = true; } - if (anyChanged) { - ArrayRef<ObjCProtocolDecl *> protocols( - objcObjectType->qual_begin(), - objcObjectType->getNumProtocols()); - return ctx.getObjCObjectType(objcObjectType->getBaseType(), - newTypeArgs, protocols, - objcObjectType->isKindOfTypeAsWritten()); - } + newTypeArgs.push_back(newTypeArg); } - return type; + if (anyChanged) { + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), objcObjectType->getNumProtocols()); + return Ctx.getObjCObjectType(objcObjectType->getBaseType(), newTypeArgs, + protocols, + objcObjectType->isKindOfTypeAsWritten()); + } } - return type; - }); + return BaseType::VisitObjCObjectType(objcObjectType); + } + + QualType VisitAttributedType(const AttributedType *attrType) { + QualType newType = BaseType::VisitAttributedType(attrType); + if (newType.isNull()) + return {}; + + const auto *newAttrType = dyn_cast<AttributedType>(newType.getTypePtr()); + if (!newAttrType || newAttrType->getAttrKind() != attr::ObjCKindOf) + return newType; + + // Find out if it's an Objective-C object or object pointer type; + QualType newEquivType = newAttrType->getEquivalentType(); + const ObjCObjectPointerType *ptrType = + newEquivType->getAs<ObjCObjectPointerType>(); + const ObjCObjectType *objType = ptrType + ? ptrType->getObjectType() + : newEquivType->getAs<ObjCObjectType>(); + if (!objType) + return newType; + + // Rebuild the "equivalent" type, which pushes __kindof down into + // the object type. + newEquivType = Ctx.getObjCObjectType( + objType->getBaseType(), objType->getTypeArgsAsWritten(), + objType->getProtocols(), + // There is no need to apply kindof on an unqualified id type. + /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true); + + // If we started with an object pointer type, rebuild it. + if (ptrType) + newEquivType = Ctx.getObjCObjectPointerType(newEquivType); + + // Rebuild the attributed type. + return Ctx.getAttributedType(newAttrType->getAttrKind(), + newAttrType->getModifiedType(), newEquivType); + } +}; + +struct StripObjCKindOfTypeVisitor + : public SimpleTransformVisitor<StripObjCKindOfTypeVisitor> { + using BaseType = SimpleTransformVisitor<StripObjCKindOfTypeVisitor>; + + explicit StripObjCKindOfTypeVisitor(ASTContext &ctx) : BaseType(ctx) {} + + QualType VisitObjCObjectType(const ObjCObjectType *objType) { + if (!objType->isKindOfType()) + return BaseType::VisitObjCObjectType(objType); + + QualType baseType = objType->getBaseType().stripObjCKindOfType(Ctx); + return Ctx.getObjCObjectType(baseType, objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/false); + } +}; + +} // namespace + +/// Substitute the given type arguments for Objective-C type +/// parameters within the given type, recursively. +QualType QualType::substObjCTypeArgs(ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const { + SubstObjCTypeArgsVisitor visitor(ctx, typeArgs, context); + return visitor.recurse(*this); } QualType QualType::substObjCMemberType(QualType objectType, @@ -1337,25 +1377,8 @@ QualType QualType::substObjCMemberType(QualType objectType, QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { // FIXME: Because ASTContext::getAttributedType() is non-const. auto &ctx = const_cast<ASTContext &>(constCtx); - return simpleTransform(ctx, *this, - [&](QualType type) -> QualType { - SplitQualType splitType = type.split(); - if (auto *objType = splitType.Ty->getAs<ObjCObjectType>()) { - if (!objType->isKindOfType()) - return type; - - QualType baseType - = objType->getBaseType().stripObjCKindOfType(ctx); - return ctx.getQualifiedType( - ctx.getObjCObjectType(baseType, - objType->getTypeArgsAsWritten(), - objType->getProtocols(), - /*isKindOf=*/false), - splitType.Quals); - } - - return type; - }); + StripObjCKindOfTypeVisitor visitor(ctx); + return visitor.recurse(*this); } QualType QualType::getAtomicUnqualifiedType() const { @@ -1713,9 +1736,17 @@ namespace { return Visit(T->getModifiedType()); } + Type *VisitMacroQualifiedType(const MacroQualifiedType *T) { + return Visit(T->getUnderlyingType()); + } + Type *VisitAdjustedType(const AdjustedType *T) { return Visit(T->getOriginalType()); } + + Type *VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } }; } // namespace @@ -2245,6 +2276,18 @@ bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { getObjCLifetime() != Qualifiers::OCL_Weak; } +bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD) { + return RD->hasNonTrivialToPrimitiveDefaultInitializeCUnion(); +} + +bool QualType::hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD) { + return RD->hasNonTrivialToPrimitiveDestructCUnion(); +} + +bool QualType::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) { + return RD->hasNonTrivialToPrimitiveCopyCUnion(); +} + QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { if (const auto *RT = @@ -2990,6 +3033,7 @@ CanThrowResult FunctionProtoType::canThrow() const { case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue: + case EST_NoThrow: return CT_Cannot; case EST_None: @@ -3082,6 +3126,20 @@ QualType TypedefType::desugar() const { return getDecl()->getUnderlyingType(); } +QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } + +QualType MacroQualifiedType::getModifiedType() const { + // Step over MacroQualifiedTypes from the same macro to find the type + // ultimately qualified by the macro qualifier. + QualType Inner = cast<AttributedType>(getUnderlyingType())->getModifiedType(); + while (auto *InnerMQT = dyn_cast<MacroQualifiedType>(Inner)) { + if (InnerMQT->getMacroIdentifier() != getMacroIdentifier()) + break; + Inner = InnerMQT->getModifiedType(); + } + return Inner; +} + TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, E->isTypeDependent(), E->isInstantiationDependent(), @@ -3206,6 +3264,7 @@ bool AttributedType::isQualifier() const { case attr::TypeNullable: case attr::TypeNullUnspecified: case attr::LifetimeBound: + case attr::AddressSpace: return true; // All other type attributes aren't qualifiers; they rewrite the modified @@ -3831,7 +3890,11 @@ AttributedType::getImmediateNullability() const { } Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) { - if (auto attributed = dyn_cast<AttributedType>(T.getTypePtr())) { + QualType AttrTy = T; + if (auto MacroTy = dyn_cast<MacroQualifiedType>(T)) + AttrTy = MacroTy->getUnderlyingType(); + + if (auto attributed = dyn_cast<AttributedType>(AttrTy)) { if (auto nullability = attributed->getImmediateNullability()) { T = attributed->getModifiedType(); return nullability; @@ -4016,25 +4079,8 @@ CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { void clang::FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val, unsigned Scale) { - if (Val.isSigned() && Val.isNegative() && Val != -Val) { - Val = -Val; - Str.push_back('-'); - } - - llvm::APSInt IntPart = Val >> Scale; - - // Add 4 digits to hold the value after multiplying 10 (the radix) - unsigned Width = Val.getBitWidth() + 4; - llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); - llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width); - llvm::APInt RadixInt = llvm::APInt(Width, 10); - - IntPart.toString(Str, /*radix=*/10); - Str.push_back('.'); - do { - (FractPart * RadixInt) - .lshr(Scale) - .toString(Str, /*radix=*/10, Val.isSigned()); - FractPart = (FractPart * RadixInt) & FractPartMask; - } while (FractPart != 0); + FixedPointSemantics FXSema(Val.getBitWidth(), Scale, Val.isSigned(), + /*IsSaturated=*/false, + /*HasUnsignedPadding=*/false); + APFixedPoint(Val, FXSema).toString(Str); } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index b7b2f188d7160..abe4c4eb25e6f 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -1,9 +1,8 @@ //===- TypeLoc.cpp - Type Source Info Wrapper -----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 32c75afb43812..8d5c37299e5fb 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1,9 +1,8 @@ //===- TypePrinter.cpp - Pretty-Print Clang Types -------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -258,11 +257,18 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::FunctionProto: case Type::FunctionNoProto: case Type::Paren: - case Type::Attributed: case Type::PackExpansion: case Type::SubstTemplateTypeParm: + case Type::MacroQualified: CanPrefixQualifiers = false; break; + + case Type::Attributed: { + // We still want to print the address_space before the type if it is an + // address_space attribute. + const auto *AttrTy = cast<AttributedType>(T); + CanPrefixQualifiers = AttrTy->getAttrKind() == attr::AddressSpace; + } } return CanPrefixQualifiers; @@ -728,6 +734,8 @@ FunctionProtoType::printExceptionSpecification(raw_ostream &OS, OS << getExceptionType(I).stream(Policy); } OS << ')'; + } else if (EST_NoThrow == getExceptionSpecType()) { + OS << " __attribute__((nothrow))"; } else if (isNoexceptExceptionSpec(getExceptionSpecType())) { OS << " noexcept"; // FIXME:Is it useful to print out the expression for a non-dependent @@ -810,8 +818,8 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, printFunctionAfter(Info, OS); - if (!T->getTypeQuals().empty()) - OS << " " << T->getTypeQuals().getAsString(); + if (!T->getMethodQuals().empty()) + OS << " " << T->getMethodQuals().getAsString(); switch (T->getRefQualifier()) { case RQ_None: @@ -958,6 +966,21 @@ void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { printTypeSpec(T->getDecl(), OS); } +void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T, + raw_ostream &OS) { + StringRef MacroName = T->getMacroIdentifier()->getName(); + OS << MacroName << " "; + + // Since this type is meant to print the macro instead of the whole attribute, + // we trim any attributes and go directly to the original modified type. + printBefore(T->getModifiedType(), OS); +} + +void TypePrinter::printMacroQualifiedAfter(const MacroQualifiedType *T, + raw_ostream &OS) { + printAfter(T->getModifiedType(), OS); +} + void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {} void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T, @@ -1212,8 +1235,18 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, raw_ostream &OS) { if (IdentifierInfo *Id = T->getIdentifier()) OS << Id->getName(); - else - OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); + else { + bool IsLambdaAutoParam = false; + if (auto D = T->getDecl()) { + if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext())) + IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda(); + } + + if (IsLambdaAutoParam) + OS << "auto"; + else + OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); + } spaceBeforePlaceHolder(OS); } @@ -1378,7 +1411,10 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, if (T->getAttrKind() == attr::ObjCKindOf) OS << "__kindof "; - printBefore(T->getModifiedType(), OS); + if (T->getAttrKind() == attr::AddressSpace) + printBefore(T->getEquivalentType(), OS); + else + printBefore(T->getModifiedType(), OS); if (T->isMSTypeSpec()) { switch (T->getAttrKind()) { @@ -1624,6 +1660,19 @@ static const TemplateArgument &getArgument(const TemplateArgumentLoc &A) { return A.getArgument(); } +static void printArgument(const TemplateArgument &A, const PrintingPolicy &PP, + llvm::raw_ostream &OS) { + A.print(PP, OS); +} + +static void printArgument(const TemplateArgumentLoc &A, + const PrintingPolicy &PP, llvm::raw_ostream &OS) { + const TemplateArgument::ArgKind &Kind = A.getArgument().getKind(); + if (Kind == TemplateArgument::ArgKind::Type) + return A.getTypeSourceInfo()->getType().print(OS, PP); + return A.getArgument().print(PP, OS); +} + template<typename TA> static void printTo(raw_ostream &OS, ArrayRef<TA> Args, const PrintingPolicy &Policy, bool SkipBrackets) { @@ -1645,7 +1694,8 @@ static void printTo(raw_ostream &OS, ArrayRef<TA> Args, } else { if (!FirstArg) OS << Comma; - Argument.print(Policy, ArgOS); + // Tries to print the argument with location info if exists. + printArgument(Arg, Policy, ArgOS); } StringRef ArgString = ArgOS.str(); @@ -1755,17 +1805,19 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, case LangAS::opencl_private: break; case LangAS::opencl_constant: - case LangAS::cuda_constant: OS << "__constant"; break; case LangAS::opencl_generic: OS << "__generic"; break; case LangAS::cuda_device: - OS << "__device"; + OS << "__device__"; + break; + case LangAS::cuda_constant: + OS << "__constant__"; break; case LangAS::cuda_shared: - OS << "__shared"; + OS << "__shared__"; break; default: OS << "__attribute__((address_space("; diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp index a3f3dbdfb4f93..53d0ef09f14c5 100644 --- a/lib/AST/VTTBuilder.cpp +++ b/lib/AST/VTTBuilder.cpp @@ -1,9 +1,8 @@ //===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 846a6085743e1..0c699571555d5 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -1,9 +1,8 @@ //===--- VTableBuilder.cpp - C++ vtable layout builder --------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -480,7 +479,7 @@ static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, // Force the signatures to match. We can't rely on the overrides // list here because there isn't necessarily an inheritance // relationship between the two methods. - if (LT->getTypeQuals() != RT->getTypeQuals()) + if (LT->getMethodQuals() != RT->getMethodQuals()) return false; return LT->getParamTypes() == RT->getParamTypes(); } @@ -847,6 +846,8 @@ private: : BaseOffset(CharUnits::Zero()), BaseOffsetInLayoutClass(CharUnits::Zero()), VTableIndex(0) { } + + MethodInfo(MethodInfo const&) = default; }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -1061,8 +1062,7 @@ void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD, SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD]; // Check if we have this thunk already. - if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != - ThunksVector.end()) + if (llvm::find(ThunksVector, Thunk) != ThunksVector.end()) return; ThunksVector.push_back(Thunk); @@ -1272,7 +1272,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment( // We don't have vcall offsets for this virtual base, go ahead and // build them. VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, - /*FinalOverriders=*/nullptr, + /*Overriders=*/nullptr, BaseSubobject(Offset.VirtualBase, CharUnits::Zero()), /*BaseIsVirtual=*/true, @@ -2245,7 +2245,7 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, if (I != VirtualBaseClassOffsetOffsets.end()) return I->second; - VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/nullptr, + VCallAndVBaseOffsetBuilder Builder(RD, RD, /*Overriders=*/nullptr, BaseSubobject(RD, CharUnits::Zero()), /*BaseIsVirtual=*/false, /*OffsetInLayoutClass=*/CharUnits::Zero()); @@ -2451,8 +2451,7 @@ private: SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; // Check if we have this thunk already. - if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != - ThunksVector.end()) + if (llvm::find(ThunksVector, Thunk) != ThunksVector.end()) return; ThunksVector.push_back(Thunk); @@ -3189,8 +3188,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) { const CXXMethodDecl *MD = MethodNameAndDecl.second; ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::stable_sort(ThunksVector.begin(), ThunksVector.end(), - [](const ThunkInfo &LHS, const ThunkInfo &RHS) { + llvm::stable_sort(ThunksVector, [](const ThunkInfo &LHS, + const ThunkInfo &RHS) { // Keep different thunks with the same adjustments in the order they // were put into the vector. return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); |