Index: bindings/python/clang/cindex.py =================================================================== --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -305,6 +305,14 @@ Error = 3 Fatal = 4 + DisplaySourceLocation = 0x01 + DisplayColumn = 0x02 + DisplaySourceRanges = 0x04 + DisplayOption = 0x08 + DisplayCategoryId = 0x10 + DisplayCategoryName = 0x20 + _FormatOptionsMask = 0x3f + def __init__(self, ptr): self.ptr = ptr @@ -399,10 +407,27 @@ return conf.lib.clang_getCString(disable) + def format(self, options=None): + """ + Format this diagnostic for display. The options argument takes + Diagnostic.Display* flags, which can be combined using bitwise OR. If + the options argument is not provided, the default display options will + be used. + """ + if options is None: + options = conf.lib.clang_defaultDiagnosticDisplayOptions() + if options & ~Diagnostic._FormatOptionsMask: + raise ValueError('Invalid format options') + formatted = conf.lib.clang_formatDiagnostic(self, options) + return conf.lib.clang_getCString(formatted) + def __repr__(self): return "" % ( self.severity, self.location, self.spelling) + def __str__(self): + return self.format() + def from_param(self): return self.ptr @@ -3012,6 +3037,10 @@ [Cursor], bool), + ("clang_defaultDiagnosticDisplayOptions", + [], + c_uint), + ("clang_defaultSaveOptions", [TranslationUnit], c_uint), @@ -3053,6 +3082,10 @@ [Type, Type], bool), + ("clang_formatDiagnostic", + [Diagnostic, c_uint], + _CXString), + ("clang_getArgType", [Type, c_uint], Type, Index: include/clang/AST/CXXInheritance.h =================================================================== --- include/clang/AST/CXXInheritance.h +++ include/clang/AST/CXXInheritance.h @@ -172,7 +172,7 @@ /// paths for a derived-to-base search. explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true, bool DetectVirtual = true) - : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + : Origin(), FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), DetectVirtual(DetectVirtual), DetectedVirtual(nullptr), NumDeclsFound(0) {} Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -251,7 +251,7 @@ // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } - void printName(raw_ostream &os) const { os << Name; } + virtual void printName(raw_ostream &os) const; /// getDeclName - Get the actual, stored name of the declaration, /// which may be a special name. @@ -1025,7 +1025,7 @@ /// void foo() { int x; static int y; extern int z; } /// bool isLocalVarDecl() const { - if (getKind() != Decl::Var) + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; if (const DeclContext *DC = getLexicalDeclContext()) return DC->getRedeclContext()->isFunctionOrMethod(); @@ -1040,7 +1040,7 @@ /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but /// excludes variables declared in blocks. bool isFunctionOrMethodVarDecl() const { - if (getKind() != Decl::Var) + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; const DeclContext *DC = getLexicalDeclContext()->getRedeclContext(); return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -1147,6 +1147,12 @@ /// \note This does NOT include a check for union-ness. bool isEmpty() const { return data().Empty; } + /// \brief Determine whether this class has direct non-static data members. + bool hasDirectFields() const { + auto &D = data(); + return D.HasPublicFields || D.HasProtectedFields || D.HasPrivateFields; + } + /// Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. bool isPolymorphic() const { return data().Polymorphic; } @@ -3408,6 +3414,8 @@ static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decl::Binding; } + + friend class ASTDeclReader; }; /// A decomposition declaration. For instance, given: @@ -3451,10 +3459,13 @@ return llvm::makeArrayRef(getTrailingObjects(), NumBindings); } + void printName(raw_ostream &os) const override; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decomposition; } friend TrailingObjects; + friend class ASTDeclReader; }; /// An instance of this class represents the declaration of a property Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -4011,6 +4011,12 @@ // within a default initializer. if (isa(ExtendingDecl)) return SD_Automatic; + // FIXME: This only works because storage class specifiers are not allowed + // on decomposition declarations. + if (isa(ExtendingDecl)) + return ExtendingDecl->getDeclContext()->isFunctionOrMethod() + ? SD_Automatic + : SD_Static; return cast(ExtendingDecl)->getStorageDuration(); } Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -264,10 +264,12 @@ /// \returns false if the visitation was terminated early, true otherwise. bool TraverseConstructorInitializer(CXXCtorInitializer *Init); - /// \brief Recursively visit a lambda capture. + /// \brief Recursively visit a lambda capture. \c Init is the expression that + /// will be used to initialize the capture. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C); + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init); /// \brief Recursively visit the body of a lambda expression. /// @@ -885,9 +887,12 @@ template bool RecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE, - const LambdaCapture *C) { + const LambdaCapture *C, + Expr *Init) { if (LE->isInitCapture(C)) TRY_TO(TraverseDecl(C->getCapturedVar())); + else + TRY_TO(TraverseStmt(Init)); return true; } @@ -2261,13 +2266,11 @@ // Walk only the visible parts of lambda expressions. DEF_TRAVERSE_STMT(LambdaExpr, { - for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), - CEnd = S->explicit_capture_end(); - C != CEnd; ++C) { - TRY_TO(TraverseLambdaCapture(S, C)); - } - for (Expr *Init : S->capture_inits()) { - TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Init); + for (unsigned I = 0, N = S->capture_size(); I != N; ++I) { + const LambdaCapture *C = S->capture_begin() + I; + if (C->isExplicit() || getDerived().shouldVisitImplicitCode()) { + TRY_TO(TraverseLambdaCapture(S, C, S->capture_init_begin()[I])); + } } TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); Index: include/clang/AST/UnresolvedSet.h =================================================================== --- include/clang/AST/UnresolvedSet.h +++ include/clang/AST/UnresolvedSet.h @@ -38,7 +38,7 @@ : iterator_adaptor_base(const_cast(Iter)) {} public: - UnresolvedSetIterator() {} + UnresolvedSetIterator() = default; NamedDecl *getDecl() const { return I->getDecl(); } void setDecl(NamedDecl *ND) const { return I->setDecl(ND); } Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -828,8 +828,6 @@ InGroup; // @available(...) -def err_avail_query_expected_condition : Error< - "expected an availability condition here">; def err_avail_query_expected_platform_name : Error< "expected a platform name here">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -385,6 +385,40 @@ "decomposition declaration template not supported">; def err_decomp_decl_not_alone : Error< "decomposition declaration must be the only declaration in its group">; +def err_decomp_decl_requires_init : Error< + "decomposition declaration %0 requires an initializer">; +def err_decomp_decl_paren_init : Error< + "decomposition declaration %0 cannot have a parenthesized initializer">; +def err_decomp_decl_wrong_number_bindings : Error< + "type %0 decomposes into %2 elements, but %select{only |}3%1 " + "names were provided">; +def err_decomp_decl_unbindable_type : Error< + "cannot decompose %select{union|non-class, non-array}1 type %2">; +def err_decomp_decl_multiple_bases_with_members : Error< + "cannot decompose class type %1: " + "%select{its base classes %2 and|both it and its base class}0 %3 " + "have non-static data members">; +def err_decomp_decl_ambiguous_base : Error< + "cannot decompose members of ambiguous base class %1 of %0:%2">; +def err_decomp_decl_non_public_base : Error< + "cannot decompose members of non-public base class %1 of %0">; +def err_decomp_decl_non_public_member : Error< + "cannot decompose non-public member %0 of %1">; +def err_decomp_decl_anon_union_member : Error< + "cannot decompose class type %0 because it has an anonymous " + "%select{struct|union}1 member">; +def err_decomp_decl_std_tuple_element_not_specialized : Error< + "cannot decompose this type; 'std::tuple_element<%0>::type' " + "does not name a type">; +def err_decomp_decl_std_tuple_size_not_constant : Error< + "cannot decompose this type; 'std::tuple_size<%0>::value' " + "is not a valid integral constant expression">; +def note_in_binding_decl_init : Note< + "in implicit initialization of binding declaration %0">; + +def err_std_type_trait_not_class_template : Error< + "unsupported standard library implementation: " + "'std::%0' is not a class template">; // C++ using declarations def err_using_requires_qualname : Error< @@ -4282,8 +4316,6 @@ "%select{unavailable|deleted|deprecated|partial}1 here">; def note_implicitly_deleted : Note< "explicitly defaulted function was implicitly deleted here">; -def note_inherited_deleted_here : Note< - "deleted constructor was inherited here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; @@ -5455,6 +5487,9 @@ "dereference of type %1 that was reinterpret_cast from type %0 has undefined " "behavior">, InGroup, DefaultIgnore; +def warn_taking_address_of_packed_member : Warning< + "taking address of packed member %0 of class or structure %q1 may result in an unaligned pointer value">, + InGroup>; def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; Index: include/clang/Basic/SourceManager.h =================================================================== --- include/clang/Basic/SourceManager.h +++ include/clang/Basic/SourceManager.h @@ -1357,7 +1357,7 @@ } /// \brief Returns whether \p Loc is expanded from a macro in a system header. - bool isInSystemMacro(SourceLocation loc) { + bool isInSystemMacro(SourceLocation loc) const { return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc)); } Index: include/clang/Basic/VirtualFileSystem.h =================================================================== --- include/clang/Basic/VirtualFileSystem.h +++ include/clang/Basic/VirtualFileSystem.h @@ -340,6 +340,7 @@ Optional IsCaseSensitive; Optional IsOverlayRelative; Optional UseExternalNames; + Optional IgnoreNonExistentContents; std::string OverlayDir; public: @@ -351,6 +352,9 @@ void setUseExternalNames(bool UseExtNames) { UseExternalNames = UseExtNames; } + void setIgnoreNonExistentContents(bool IgnoreContents) { + IgnoreNonExistentContents = IgnoreContents; + } void setOverlayDir(StringRef OverlayDirectory) { IsOverlayRelative = true; OverlayDir.assign(OverlayDirectory.str()); Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -84,7 +84,10 @@ EK_RelatedResult, /// \brief The entity being initialized is a function parameter; function /// is member of group of audited CF APIs. - EK_Parameter_CF_Audited + EK_Parameter_CF_Audited, + /// \brief The entity being initialized is a structured binding of a + /// decomposition declaration. + EK_Binding, // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this // enum as an index for its first %select. When modifying this list, @@ -126,9 +129,9 @@ }; union { - /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or - /// FieldDecl, respectively. - DeclaratorDecl *VariableOrMember; + /// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the VarDecl, + /// FieldDecl or BindingDecl, respectively. + ValueDecl *VariableOrMember; /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where /// result type was implicitly changed to accommodate ARC semantics. @@ -180,6 +183,11 @@ : Kind(EK_Member), Parent(Parent), Type(Member->getType()), ManglingNumber(0), VariableOrMember(Member) { } + /// \brief Create the initialization entity for a binding. + InitializedEntity(BindingDecl *Binding, QualType Type) + : Kind(EK_Binding), Parent(nullptr), Type(Type), + ManglingNumber(0), VariableOrMember(Binding) {} + /// \brief Create the initialization entity for an array element. InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent); @@ -314,6 +322,12 @@ return InitializedEntity(Context, Index, Parent); } + /// \brief Create the initialization entity for a structured binding. + static InitializedEntity InitializeBinding(BindingDecl *Binding, + QualType Type) { + return InitializedEntity(Binding, Type); + } + /// \brief Create the initialization entity for a lambda capture. static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID, QualType FieldType, @@ -355,7 +369,7 @@ /// \brief Retrieve the variable, parameter, or field being /// initialized. - DeclaratorDecl *getDecl() const; + ValueDecl *getDecl() const; /// \brief Retrieve the ObjectiveC method being initialized. ObjCMethodDecl *getMethodDecl() const { return MethodDecl; } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1728,7 +1728,8 @@ // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); - void CheckCompleteVariableDeclaration(VarDecl *var); + void CheckCompleteVariableDeclaration(VarDecl *VD); + void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, @@ -3970,6 +3971,12 @@ bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, + SourceLocation OpLoc, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo); + ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -5772,6 +5779,10 @@ TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); + TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc); + void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); @@ -9559,6 +9570,10 @@ void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs); + /// \brief Check if we are taking the address of a packed field + /// as this may be a problem if the pointer value is dereferenced. + void CheckAddressOfPackedMember(Expr *rhs); + /// \brief The parser's current scope. /// /// The parser maintains this state here. @@ -9653,6 +9668,51 @@ // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; + +private: + /// \brief Helper class that collects misaligned member designations and + /// their location info for delayed diagnostics. + struct MisalignedMember { + Expr *E; + RecordDecl *RD; + ValueDecl *MD; + CharUnits Alignment; + + MisalignedMember() : E(), RD(), MD(), Alignment() {} + MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) + : E(E), RD(RD), MD(MD), Alignment(Alignment) {} + explicit MisalignedMember(Expr *E) + : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} + + bool operator==(const MisalignedMember &m) { return this->E == m.E; } + }; + /// \brief Small set of gathered accesses to potentially misaligned members + /// due to the packed attribute. + SmallVector MisalignedMembers; + + /// \brief Adds an expression to the set of gathered misaligned members. + void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment); + +public: + /// \brief Diagnoses the current set of gathered accesses. This typically + /// happens at full expression level. The set is cleared after emitting the + /// diagnostics. + void DiagnoseMisalignedMembers(); + + /// \brief This function checks if the expression is in the sef of potentially + /// misaligned members and it is converted to some pointer type T with lower + /// or equal alignment requirements. If so it removes it. This is used when + /// we do not want to diagnose such misaligned access (e.g. in conversions to void*). + void DiscardMisalignedMemberAddress(const Type *T, Expr *E); + + /// \brief This function calls Action when it determines that E designates a + /// misaligned member due to the packed attribute. This is used to emit + /// local diagnostics like in reference binding. + void RefersToMemberWithReducedAlignment( + Expr *E, + std::function Action); }; /// \brief RAII object that enters a new expression evaluation context. Index: include/clang/Sema/Template.h =================================================================== --- include/clang/Sema/Template.h +++ include/clang/Sema/Template.h @@ -433,7 +433,8 @@ Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams); Decl *VisitDecl(Decl *D); - Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate); + Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate, + ArrayRef *Bindings = nullptr); // Enable late instantiation of attributes. Late instantiated attributes // will be stored in LA. Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1056,6 +1056,10 @@ DECL_IMPLICIT_PARAM, /// \brief A ParmVarDecl record. DECL_PARM_VAR, + /// \brief A DecompositionDecl record. + DECL_DECOMPOSITION, + /// \brief A BindingDecl record. + DECL_BINDING, /// \brief A FileScopeAsmDecl record. DECL_FILE_SCOPE_ASM, /// \brief A BlockDecl record. Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -429,6 +429,7 @@ 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); @@ -1224,6 +1225,13 @@ dumpDecl(B); } +void ASTDumper::VisitBindingDecl(const BindingDecl *D) { + dumpName(D); + dumpType(D->getType()); + if (auto *E = D->getBinding()) + dumpStmt(E); +} + void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { dumpStmt(D->getAsmString()); } Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1395,6 +1395,10 @@ return clang::LinkageComputer::getLVForDecl(D, computation); } +void NamedDecl::printName(raw_ostream &os) const { + os << Name; +} + std::string NamedDecl::getQualifiedNameAsString() const { std::string QualName; llvm::raw_string_ostream OS(QualName); @@ -1481,7 +1485,7 @@ OS << "::"; } - if (getDeclName()) + if (getDeclName() || isa(this)) OS << *this; else OS << "(anonymous)"; @@ -3408,6 +3412,10 @@ case Builtin::BIstrlen: return Builtin::BIstrlen; + case Builtin::BI__builtin_bzero: + case Builtin::BIbzero: + return Builtin::BIbzero; + default: if (isExternC()) { if (FnInfo->isStr("memset")) @@ -3430,6 +3438,8 @@ return Builtin::BIstrndup; else if (FnInfo->isStr("strlen")) return Builtin::BIstrlen; + else if (FnInfo->isStr("bzero")) + return Builtin::BIbzero; } break; } Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -2334,8 +2334,9 @@ unsigned ID, unsigned NumBindings) { size_t Extra = additionalSizeToAlloc(NumBindings); - auto *Result = new (C, ID, Extra) DecompositionDecl( - C, nullptr, SourceLocation(), SourceLocation(), QualType(), nullptr, StorageClass(), None); + auto *Result = new (C, ID, Extra) + DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(), + QualType(), nullptr, StorageClass(), None); // Set up and clean out the bindings array. Result->NumBindings = NumBindings; auto *Trail = Result->getTrailingObjects(); @@ -2344,6 +2345,18 @@ return Result; } +void DecompositionDecl::printName(llvm::raw_ostream &os) const { + os << '['; + bool Comma = false; + for (auto *B : bindings()) { + if (Comma) + os << ", "; + B->printName(os); + Comma = true; + } + os << ']'; +} + MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3308,11 +3308,16 @@ if (Ivar->isBitField()) return Ivar; - if (DeclRefExpr *DeclRef = dyn_cast(E)) + if (DeclRefExpr *DeclRef = dyn_cast(E)) { if (FieldDecl *Field = dyn_cast(DeclRef->getDecl())) if (Field->isBitField()) return Field; + if (BindingDecl *BD = dyn_cast(DeclRef->getDecl())) + if (Expr *E = BD->getBinding()) + return E->getSourceBitField(); + } + if (BinaryOperator *BinOp = dyn_cast(E)) { if (BinOp->isAssignmentOp() && BinOp->getLHS()) return BinOp->getLHS()->getSourceBitField(); @@ -3329,6 +3334,7 @@ } bool Expr::refersToVectorElement() const { + // FIXME: Why do we not just look at the ObjectKind here? const Expr *E = this->IgnoreParens(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { @@ -3345,6 +3351,11 @@ if (isa(E)) return true; + if (auto *DRE = dyn_cast(E)) + if (auto *BD = dyn_cast(DRE->getDecl())) + if (auto *E = BD->getBinding()) + return E->refersToVectorElement(); + return false; } Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -429,6 +429,7 @@ else islvalue = isa(D) || isa(D) || isa(D) || + isa(D) || (Ctx.getLangOpts().CPlusPlus && (isa(D) || isa(D) || isa(D))); Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -3427,6 +3427,18 @@ Val = APValue(); return false; } + + // Evaluate initializers for any structured bindings. + if (auto *DD = dyn_cast(VD)) { + for (auto *BD : DD->bindings()) { + APValue &Val = Info.CurrentCall->createTemporary(BD, true); + + LValue Result; + if (!EvaluateLValue(BD->getBinding(), Result, Info)) + return false; + Result.moveInto(Val); + } + } } return true; @@ -4724,6 +4736,7 @@ LValueExprEvaluatorBaseTy(Info, Result) {} bool VisitVarDecl(const Expr *E, const VarDecl *VD); + bool VisitBindingDecl(const Expr *E, const BindingDecl *BD); bool VisitUnaryPreIncDec(const UnaryOperator *UO); bool VisitDeclRefExpr(const DeclRefExpr *E); @@ -4785,6 +4798,8 @@ return Success(FD); if (const VarDecl *VD = dyn_cast(E->getDecl())) return VisitVarDecl(E, VD); + if (const BindingDecl *BD = dyn_cast(E->getDecl())) + return VisitBindingDecl(E, BD); return Error(E); } @@ -4812,6 +4827,53 @@ return Success(*V, E); } +bool LValueExprEvaluator::VisitBindingDecl(const Expr *E, + const BindingDecl *BD) { + // If we've already evaluated the binding, just return the lvalue. + if (APValue *Value = Info.CurrentCall->getTemporary(BD)) { + if (Value->isUninit()) { + if (!Info.checkingPotentialConstantExpression()) + Info.FFDiag(E, diag::note_constexpr_use_uninit_reference); + return false; + } + return Success(*Value, E); + } + + // We've not evaluated the initializer of this binding. It's still OK if it + // is initialized by a constant expression. + // + // FIXME: We should check this at the point of declaration, since we're not + // supposed to be able to use it if it references something that was declared + // later. + auto *Binding = BD->getBinding(); + if (!Binding) { + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + } + + // Evaluate in an independent context to check whether the binding was a + // constant expression in an absolute sense, and without mutating any of + // our local state. + Expr::EvalStatus InitStatus; + SmallVector Diag; + InitStatus.Diag = &Diag; + EvalInfo InitInfo(Info.Ctx, InitStatus, EvalInfo::EM_ConstantExpression); + + if (!EvaluateLValue(Binding, Result, InitInfo) || InitStatus.HasSideEffects || + !CheckLValueConstantExpression( + InitInfo, Binding->getExprLoc(), + Info.Ctx.getLValueReferenceType(BD->getType()), Result) || + !Diag.empty()) { + // FIXME: Diagnose this better. Maybe produce the Diags to explain why + // the initializer was not constant. + if (!Info.checkingPotentialConstantExpression()) + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + } + + return true; +} + bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { // Walk through the expression to find the materialized temporary itself. Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -396,6 +396,7 @@ REGISTER_MATCHER(templateName); REGISTER_MATCHER(templateArgumentCountIs); REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(templateTypeParmDecl); REGISTER_MATCHER(templateTypeParmType); REGISTER_MATCHER(throughUsingDecl); REGISTER_MATCHER(to); Index: lib/Analysis/CloneDetection.cpp =================================================================== --- lib/Analysis/CloneDetection.cpp +++ lib/Analysis/CloneDetection.cpp @@ -249,8 +249,11 @@ }) //--- Calls --------------------------------------------------------------// - DEF_ADD_DATA(CallExpr, - { addData(S->getDirectCallee()->getQualifiedNameAsString()); }) + DEF_ADD_DATA(CallExpr, { + // Function pointers don't have a callee and we just skip hashing it. + if (S->getDirectCallee()) + addData(S->getDirectCallee()->getQualifiedNameAsString()); + }) //--- Exceptions ---------------------------------------------------------// DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); }) Index: lib/Basic/VirtualFileSystem.cpp =================================================================== --- lib/Basic/VirtualFileSystem.cpp +++ lib/Basic/VirtualFileSystem.cpp @@ -801,6 +801,7 @@ /// 'case-sensitive': /// 'use-external-names': /// 'overlay-relative': +/// 'ignore-non-existent-contents': /// /// Virtual directories are represented as /// \verbatim @@ -860,6 +861,14 @@ /// \brief Whether to use to use the value of 'external-contents' for the /// names of files. This global value is overridable on a per-file basis. bool UseExternalNames = true; + + /// \brief Whether an invalid path obtained via 'external-contents' should + /// cause iteration on the VFS to stop. If 'true', the VFS should ignore + /// the entry and continue with the next. Allows YAML files to be shared + /// across multiple compiler invocations regardless of prior existent + /// paths in 'external-contents'. This global value is overridable on a + /// per-file basis. + bool IgnoreNonExistentContents = true; /// @} /// Virtual file paths and external files could be canonicalized without "..", @@ -937,6 +946,10 @@ return ExternalContentsPrefixDir; } + bool ignoreNonExistentContents() const { + return IgnoreNonExistentContents; + } + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { for (const std::unique_ptr &Root : Roots) @@ -1301,6 +1314,7 @@ KeyStatusPair("case-sensitive", false), KeyStatusPair("use-external-names", false), KeyStatusPair("overlay-relative", false), + KeyStatusPair("ignore-non-existent-contents", false), KeyStatusPair("roots", true), }; @@ -1359,6 +1373,9 @@ } else if (Key == "use-external-names") { if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) return false; + } else if (Key == "ignore-non-existent-contents") { + if (!parseScalarBool(I->getValue(), FS->IgnoreNonExistentContents)) + return false; } else { llvm_unreachable("key missing from Keys"); } @@ -1619,7 +1636,7 @@ JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} void write(ArrayRef Entries, Optional UseExternalNames, Optional IsCaseSensitive, Optional IsOverlayRelative, - StringRef OverlayDir); + Optional IgnoreNonExistentContents, StringRef OverlayDir); }; } @@ -1675,6 +1692,7 @@ Optional UseExternalNames, Optional IsCaseSensitive, Optional IsOverlayRelative, + Optional IgnoreNonExistentContents, StringRef OverlayDir) { using namespace llvm::sys; @@ -1692,6 +1710,9 @@ OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false") << "',\n"; } + if (IgnoreNonExistentContents.hasValue()) + OS << " 'ignore-non-existent-contents': '" + << (IgnoreNonExistentContents.getValue() ? "true" : "false") << "',\n"; OS << " 'roots': [\n"; if (!Entries.empty()) { @@ -1748,7 +1769,8 @@ }); JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive, - IsOverlayRelative, OverlayDir); + IsOverlayRelative, IgnoreNonExistentContents, + OverlayDir); } VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( Index: lib/CodeGen/CGBlocks.cpp =================================================================== --- lib/CodeGen/CGBlocks.cpp +++ lib/CodeGen/CGBlocks.cpp @@ -125,10 +125,15 @@ llvm::Constant *init = llvm::ConstantStruct::getAnon(elements); + unsigned AddrSpace = 0; + if (C.getLangOpts().OpenCL) + AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant); llvm::GlobalVariable *global = new llvm::GlobalVariable(CGM.getModule(), init->getType(), true, llvm::GlobalValue::InternalLinkage, - init, "__block_descriptor_tmp"); + init, "__block_descriptor_tmp", nullptr, + llvm::GlobalValue::NotThreadLocal, + AddrSpace); return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } @@ -927,7 +932,10 @@ UnsignedLongTy, UnsignedLongTy, nullptr); // Now form a pointer to that. - BlockDescriptorType = llvm::PointerType::getUnqual(BlockDescriptorType); + unsigned AddrSpace = 0; + if (getLangOpts().OpenCL) + AddrSpace = getContext().getTargetAddressSpace(LangAS::opencl_constant); + BlockDescriptorType = llvm::PointerType::get(BlockDescriptorType, AddrSpace); return BlockDescriptorType; } Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -632,8 +632,7 @@ void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool isPIEDefault() const override { return true; } - + bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; SanitizerMask getDefaultSanitizers() const override; Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -3344,6 +3344,19 @@ return new tools::cloudabi::Linker(*this); } +bool CloudABI::isPIEDefault() const { + // Only enable PIE on architectures that support PC-relative + // addressing. PC-relative addressing is required, as the process + // startup code must be able to relocate itself. + switch (getTriple().getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::x86_64: + return true; + default: + return false; + } +} + SanitizerMask CloudABI::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::SafeStack; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3242,7 +3242,7 @@ break; } - if (Triple.isOSLinux()) { + if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. case llvm::Triple::mips64: @@ -7523,11 +7523,13 @@ // CloudABI only supports static linkage. CmdArgs.push_back("-Bstatic"); - - // CloudABI uses Position Independent Executables exclusively. - CmdArgs.push_back("-pie"); CmdArgs.push_back("--no-dynamic-linker"); - CmdArgs.push_back("-zrelro"); + + // Provide PIE linker flags in case PIE is default for the architecture. + if (ToolChain.isPIEDefault()) { + CmdArgs.push_back("-pie"); + CmdArgs.push_back("-zrelro"); + } CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("--gc-sections"); Index: lib/Frontend/ModuleDependencyCollector.cpp =================================================================== --- lib/Frontend/ModuleDependencyCollector.cpp +++ lib/Frontend/ModuleDependencyCollector.cpp @@ -134,6 +134,10 @@ // allows crash reproducer scripts to work across machines. VFSWriter.setOverlayDir(VFSDir); + // Do not ignore non existent contents otherwise we might skip something + // that should have been collected here. + VFSWriter.setIgnoreNonExistentContents(false); + // Explicitly set case sensitivity for the YAML writer. For that, find out // the sensitivity at the path where the headers all collected to. VFSWriter.setCaseSensitivity(isCaseSensitivePath(VFSDir)); Index: lib/Index/IndexBody.cpp =================================================================== --- lib/Index/IndexBody.cpp +++ lib/Index/IndexBody.cpp @@ -276,7 +276,8 @@ return true; } - bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) { + bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C, + Expr *Init) { if (C->capturesThis() || C->capturesVLAType()) return true; Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -28,6 +28,7 @@ #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" @@ -809,6 +810,7 @@ diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); + // No initialization is performed for a tentative definition. CheckCompleteVariableDeclaration(VD); // Notify the consumer that we've completed a tentative definition. Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -256,6 +256,7 @@ Op.CheckConstCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.SrcExpr.get(), DestTInfo, @@ -279,6 +280,7 @@ Op.CheckReinterpretCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), @@ -291,6 +293,7 @@ Op.CheckStaticCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType, Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -6179,13 +6179,15 @@ // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3); + unsigned ExpectedNumArgs = + (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3); if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (BId == Builtin::BImemset || + unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); - unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2); + unsigned LenArg = + (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); if (CheckMemorySizeofForComparison(*this, LenExpr, FnName, @@ -6197,6 +6199,13 @@ const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); llvm::FoldingSetNodeID SizeOfArgID; + // Although widely used, 'bzero' is not a standard function. Be more strict + // with the argument types before allowing diagnostics and only allow the + // form bzero(ptr, sizeof(...)). + QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType(); + if (BId == Builtin::BIbzero && !FirstArgTy->getAs()) + return; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); @@ -8374,6 +8383,8 @@ DiagnoseNullConversion(S, E, T, CC); + S.DiscardMisalignedMemberAddress(Target, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -9444,6 +9455,7 @@ CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); + DiagnoseMisalignedMembers(); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, @@ -10989,3 +11001,67 @@ << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } + +void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) { + MisalignedMembers.emplace_back(E, RD, MD, Alignment); +} + +void Sema::DiagnoseMisalignedMembers() { + for (MisalignedMember &m : MisalignedMembers) { + Diag(m.E->getLocStart(), diag::warn_taking_address_of_packed_member) + << m.MD << m.RD << m.E->getSourceRange(); + } + MisalignedMembers.clear(); +} + +void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { + if (!T->isPointerType()) + return; + if (isa(E) && + cast(E)->getOpcode() == UO_AddrOf) { + auto *Op = cast(E)->getSubExpr()->IgnoreParens(); + if (isa(Op)) { + auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), + MisalignedMember(Op)); + if (MA != MisalignedMembers.end() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment) + MisalignedMembers.erase(MA); + } + } +} + +void Sema::RefersToMemberWithReducedAlignment( + Expr *E, + std::function Action) { + const auto *ME = dyn_cast(E); + while (ME && isa(ME->getMemberDecl())) { + QualType BaseType = ME->getBase()->getType(); + if (ME->isArrow()) + BaseType = BaseType->getPointeeType(); + RecordDecl *RD = BaseType->getAs()->getDecl(); + + ValueDecl *MD = ME->getMemberDecl(); + bool ByteAligned = Context.getTypeAlignInChars(MD->getType()).isOne(); + if (ByteAligned) // Attribute packed does not have any effect. + break; + + if (!ByteAligned && + (RD->hasAttr() || (MD->hasAttr()))) { + CharUnits Alignment = std::min(Context.getTypeAlignInChars(MD->getType()), + Context.getTypeAlignInChars(BaseType)); + // Notify that this expression designates a member with reduced alignment + Action(E, RD, MD, Alignment); + break; + } + ME = dyn_cast(ME->getBase()); + } +} + +void Sema::CheckAddressOfPackedMember(Expr *rhs) { + using namespace std::placeholders; + RefersToMemberWithReducedAlignment( + rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, + _2, _3, _4)); +} + Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -43,7 +43,6 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include #include @@ -6534,157 +6533,6 @@ return NewVD; } -NamedDecl * -Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, - MultiTemplateParamsArg TemplateParamLists) { - assert(D.isDecompositionDeclarator()); - const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); - - // The syntax only allows a decomposition declarator as a simple-declaration - // or a for-range-declaration, but we parse it in more cases than that. - if (!D.mayHaveDecompositionDeclarator()) { - Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) - << Decomp.getSourceRange(); - return nullptr; - } - - if (!TemplateParamLists.empty()) { - // FIXME: There's no rule against this, but there are also no rules that - // would actually make it usable, so we reject it for now. - Diag(TemplateParamLists.front()->getTemplateLoc(), - diag::err_decomp_decl_template); - return nullptr; - } - - Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z - ? diag::warn_cxx14_compat_decomp_decl - : diag::ext_decomp_decl) - << Decomp.getSourceRange(); - - // The semantic context is always just the current context. - DeclContext *const DC = CurContext; - - // C++1z [dcl.dcl]/8: - // The decl-specifier-seq shall contain only the type-specifier auto - // and cv-qualifiers. - auto &DS = D.getDeclSpec(); - { - SmallVector BadSpecifiers; - SmallVector BadSpecifierLocs; - if (auto SCS = DS.getStorageClassSpec()) { - BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS)); - BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc()); - } - if (auto TSCS = DS.getThreadStorageClassSpec()) { - BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS)); - BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); - } - if (DS.isConstexprSpecified()) { - BadSpecifiers.push_back("constexpr"); - BadSpecifierLocs.push_back(DS.getConstexprSpecLoc()); - } - if (DS.isInlineSpecified()) { - BadSpecifiers.push_back("inline"); - BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); - } - if (!BadSpecifiers.empty()) { - auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); - Err << (int)BadSpecifiers.size() - << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " "); - // Don't add FixItHints to remove the specifiers; we do still respect - // them when building the underlying variable. - for (auto Loc : BadSpecifierLocs) - Err << SourceRange(Loc, Loc); - } - // We can't recover from it being declared as a typedef. - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) - return nullptr; - } - - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType R = TInfo->getType(); - - if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, - UPPC_DeclarationType)) - D.setInvalidType(); - - // The syntax only allows a single ref-qualifier prior to the decomposition - // declarator. No other declarator chunks are permitted. Also check the type - // specifier here. - if (DS.getTypeSpecType() != DeclSpec::TST_auto || - D.hasGroupingParens() || D.getNumTypeObjects() > 1 || - (D.getNumTypeObjects() == 1 && - D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) { - Diag(Decomp.getLSquareLoc(), - (D.hasGroupingParens() || - (D.getNumTypeObjects() && - D.getTypeObject(0).Kind == DeclaratorChunk::Paren)) - ? diag::err_decomp_decl_parens - : diag::err_decomp_decl_type) - << R; - - // In most cases, there's no actual problem with an explicitly-specified - // type, but a function type won't work here, and ActOnVariableDeclarator - // shouldn't be called for such a type. - if (R->isFunctionType()) - D.setInvalidType(); - } - - // Build the BindingDecls. - SmallVector Bindings; - - // Build the BindingDecls. - for (auto &B : D.getDecompositionDeclarator().bindings()) { - // Check for name conflicts. - DeclarationNameInfo NameInfo(B.Name, B.NameLoc); - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, - ForRedeclaration); - LookupName(Previous, S, - /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit()); - - // It's not permitted to shadow a template parameter name. - if (Previous.isSingleResult() && - Previous.getFoundDecl()->isTemplateParameter()) { - DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), - Previous.getFoundDecl()); - Previous.clear(); - } - - bool ConsiderLinkage = DC->isFunctionOrMethod() && - DS.getStorageClassSpec() == DeclSpec::SCS_extern; - FilterLookupForScope(Previous, DC, S, ConsiderLinkage, - /*AllowInlineNamespace*/false); - if (!Previous.empty()) { - auto *Old = Previous.getRepresentativeDecl(); - Diag(B.NameLoc, diag::err_redefinition) << B.Name; - Diag(Old->getLocation(), diag::note_previous_definition); - } - - auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); - PushOnScopeChains(BD, S, true); - Bindings.push_back(BD); - ParsingInitForAutoVars.insert(BD); - } - - // There are no prior lookup results for the variable itself, because it - // is unnamed. - DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr, - Decomp.getLSquareLoc()); - LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); - - // Build the variable that holds the non-decomposed object. - bool AddToScope = true; - NamedDecl *New = - ActOnVariableDeclarator(S, D, DC, TInfo, Previous, - MultiTemplateParamsArg(), AddToScope, Bindings); - CurContext->addHiddenDecl(New); - - if (isInOpenMPDeclareTargetContext()) - checkDeclIsAllowedInOpenMPTarget(nullptr, New); - - return New; -} - /// Enum describing the %select options in diag::warn_decl_shadow. enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field }; @@ -9604,6 +9452,9 @@ assert((!VDecl || !VDecl->isInitCapture()) && "init captures are expected to be deduced prior to initialization"); + // FIXME: Deduction for a decomposition declaration does weird things if the + // initializer is an array. + ArrayRef DeduceInits = Init; if (DirectInit) { if (auto *PL = dyn_cast(Init)) @@ -9713,6 +9564,11 @@ return; } + // C++1z [dcl.dcl]p1 grammar implies that a parenthesized initializer is not + // permitted. + if (isa(VDecl) && DirectInit && isa(Init)) + Diag(VDecl->getLocation(), diag::err_decomp_decl_paren_init) << VDecl; + // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { // Attempt typo correction early so that the type of the init expression can @@ -10173,6 +10029,13 @@ if (VarDecl *Var = dyn_cast(RealDecl)) { QualType Type = Var->getType(); + // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. + if (isa(RealDecl)) { + Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; + Var->setInvalidDecl(); + return; + } + // C++11 [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) @@ -10580,6 +10443,9 @@ // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; + if (auto *DD = dyn_cast(var)) + CheckCompleteDecompositionDeclaration(DD); + QualType type = var->getType(); if (type->isDependentType()) return; @@ -10680,9 +10546,13 @@ if (!VD) return; - if (auto *DD = dyn_cast(ThisDecl)) - for (auto *BD : DD->bindings()) + if (auto *DD = dyn_cast(ThisDecl)) { + for (auto *BD : DD->bindings()) { + if (ThisDecl->isInvalidDecl()) + BD->setInvalidDecl(); FinalizeDeclaration(BD); + } + } checkAttributesAfterMerging(*this, *VD); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -39,6 +39,7 @@ #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include #include @@ -664,6 +665,750 @@ return Invalid; } +NamedDecl * +Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists) { + assert(D.isDecompositionDeclarator()); + const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); + + // The syntax only allows a decomposition declarator as a simple-declaration + // or a for-range-declaration, but we parse it in more cases than that. + if (!D.mayHaveDecompositionDeclarator()) { + Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) + << Decomp.getSourceRange(); + return nullptr; + } + + if (!TemplateParamLists.empty()) { + // FIXME: There's no rule against this, but there are also no rules that + // would actually make it usable, so we reject it for now. + Diag(TemplateParamLists.front()->getTemplateLoc(), + diag::err_decomp_decl_template); + return nullptr; + } + + Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_decomp_decl + : diag::ext_decomp_decl) + << Decomp.getSourceRange(); + + // The semantic context is always just the current context. + DeclContext *const DC = CurContext; + + // C++1z [dcl.dcl]/8: + // The decl-specifier-seq shall contain only the type-specifier auto + // and cv-qualifiers. + auto &DS = D.getDeclSpec(); + { + SmallVector BadSpecifiers; + SmallVector BadSpecifierLocs; + if (auto SCS = DS.getStorageClassSpec()) { + BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS)); + BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc()); + } + if (auto TSCS = DS.getThreadStorageClassSpec()) { + BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS)); + BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); + } + if (DS.isConstexprSpecified()) { + BadSpecifiers.push_back("constexpr"); + BadSpecifierLocs.push_back(DS.getConstexprSpecLoc()); + } + if (DS.isInlineSpecified()) { + BadSpecifiers.push_back("inline"); + BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); + } + if (!BadSpecifiers.empty()) { + auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); + Err << (int)BadSpecifiers.size() + << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " "); + // Don't add FixItHints to remove the specifiers; we do still respect + // them when building the underlying variable. + for (auto Loc : BadSpecifierLocs) + Err << SourceRange(Loc, Loc); + } + // We can't recover from it being declared as a typedef. + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) + return nullptr; + } + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType R = TInfo->getType(); + + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DeclarationType)) + D.setInvalidType(); + + // The syntax only allows a single ref-qualifier prior to the decomposition + // declarator. No other declarator chunks are permitted. Also check the type + // specifier here. + if (DS.getTypeSpecType() != DeclSpec::TST_auto || + D.hasGroupingParens() || D.getNumTypeObjects() > 1 || + (D.getNumTypeObjects() == 1 && + D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) { + Diag(Decomp.getLSquareLoc(), + (D.hasGroupingParens() || + (D.getNumTypeObjects() && + D.getTypeObject(0).Kind == DeclaratorChunk::Paren)) + ? diag::err_decomp_decl_parens + : diag::err_decomp_decl_type) + << R; + + // In most cases, there's no actual problem with an explicitly-specified + // type, but a function type won't work here, and ActOnVariableDeclarator + // shouldn't be called for such a type. + if (R->isFunctionType()) + D.setInvalidType(); + } + + // Build the BindingDecls. + SmallVector Bindings; + + // Build the BindingDecls. + for (auto &B : D.getDecompositionDeclarator().bindings()) { + // Check for name conflicts. + DeclarationNameInfo NameInfo(B.Name, B.NameLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForRedeclaration); + LookupName(Previous, S, + /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit()); + + // It's not permitted to shadow a template parameter name. + if (Previous.isSingleResult() && + Previous.getFoundDecl()->isTemplateParameter()) { + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + Previous.getFoundDecl()); + Previous.clear(); + } + + bool ConsiderLinkage = DC->isFunctionOrMethod() && + DS.getStorageClassSpec() == DeclSpec::SCS_extern; + FilterLookupForScope(Previous, DC, S, ConsiderLinkage, + /*AllowInlineNamespace*/false); + if (!Previous.empty()) { + auto *Old = Previous.getRepresentativeDecl(); + Diag(B.NameLoc, diag::err_redefinition) << B.Name; + Diag(Old->getLocation(), diag::note_previous_definition); + } + + auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); + PushOnScopeChains(BD, S, true); + Bindings.push_back(BD); + ParsingInitForAutoVars.insert(BD); + } + + // There are no prior lookup results for the variable itself, because it + // is unnamed. + DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr, + Decomp.getLSquareLoc()); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + + // Build the variable that holds the non-decomposed object. + bool AddToScope = true; + NamedDecl *New = + ActOnVariableDeclarator(S, D, DC, TInfo, Previous, + MultiTemplateParamsArg(), AddToScope, Bindings); + CurContext->addHiddenDecl(New); + + if (isInOpenMPDeclareTargetContext()) + checkDeclIsAllowedInOpenMPTarget(nullptr, New); + + return New; +} + +static bool checkSimpleDecomposition( + Sema &S, ArrayRef Bindings, ValueDecl *Src, + QualType DecompType, llvm::APSInt NumElems, QualType ElemType, + llvm::function_ref GetInit) { + if ((int64_t)Bindings.size() != NumElems) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << NumElems.toString(10) + << (NumElems < Bindings.size()); + return true; + } + + unsigned I = 0; + for (auto *B : Bindings) { + SourceLocation Loc = B->getLocation(); + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + E = GetInit(Loc, E.get(), I++); + if (E.isInvalid()) + return true; + B->setBinding(ElemType, E.get()); + } + + return false; +} + +static bool checkArrayLikeDecomposition(Sema &S, + ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + llvm::APSInt NumElems, + QualType ElemType) { + return checkSimpleDecomposition( + S, Bindings, Src, DecompType, NumElems, ElemType, + [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult { + ExprResult E = S.ActOnIntegerConstant(Loc, I); + if (E.isInvalid()) + return ExprError(); + return S.CreateBuiltinArraySubscriptExpr(Base, Loc, E.get(), Loc); + }); +} + +static bool checkArrayDecomposition(Sema &S, ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + const ConstantArrayType *CAT) { + return checkArrayLikeDecomposition(S, Bindings, Src, DecompType, + llvm::APSInt(CAT->getSize()), + CAT->getElementType()); +} + +static bool checkVectorDecomposition(Sema &S, ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + const VectorType *VT) { + return checkArrayLikeDecomposition( + S, Bindings, Src, DecompType, llvm::APSInt::get(VT->getNumElements()), + S.Context.getQualifiedType(VT->getElementType(), + DecompType.getQualifiers())); +} + +static bool checkComplexDecomposition(Sema &S, + ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + const ComplexType *CT) { + return checkSimpleDecomposition( + S, Bindings, Src, DecompType, llvm::APSInt::get(2), + S.Context.getQualifiedType(CT->getElementType(), + DecompType.getQualifiers()), + [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult { + return S.CreateBuiltinUnaryOp(Loc, I ? UO_Imag : UO_Real, Base); + }); +} + +static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, + TemplateArgumentListInfo &Args) { + SmallString<128> SS; + llvm::raw_svector_ostream OS(SS); + bool First = true; + for (auto &Arg : Args.arguments()) { + if (!First) + OS << ", "; + Arg.getArgument().print(PrintingPolicy, OS); + First = false; + } + return OS.str(); +} + +static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, + SourceLocation Loc, StringRef Trait, + TemplateArgumentListInfo &Args, + unsigned DiagID) { + auto DiagnoseMissing = [&] { + if (DiagID) + S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(), + Args); + return true; + }; + + // FIXME: Factor out duplication with lookupPromiseType in SemaCoroutine. + NamespaceDecl *Std = S.getStdNamespace(); + if (!Std) + return DiagnoseMissing(); + + // Look up the trait itself, within namespace std. We can diagnose various + // problems with this lookup even if we've been asked to not diagnose a + // missing specialization, because this can only fail if the user has been + // declaring their own names in namespace std or we don't support the + // standard library implementation in use. + LookupResult Result(S, &S.PP.getIdentifierTable().get(Trait), + Loc, Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) + return DiagnoseMissing(); + if (Result.isAmbiguous()) + return true; + + ClassTemplateDecl *TraitTD = Result.getAsSingle(); + if (!TraitTD) { + Result.suppressDiagnostics(); + NamedDecl *Found = *Result.begin(); + S.Diag(Loc, diag::err_std_type_trait_not_class_template) << Trait; + S.Diag(Found->getLocation(), diag::note_declared_at); + return true; + } + + // Build the template-id. + QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args); + if (TraitTy.isNull()) + return true; + if (!S.isCompleteType(Loc, TraitTy)) { + if (DiagID) + S.RequireCompleteType( + Loc, TraitTy, DiagID, + printTemplateArgs(S.Context.getPrintingPolicy(), Args)); + return true; + } + + CXXRecordDecl *RD = TraitTy->getAsCXXRecordDecl(); + assert(RD && "specialization of class template is not a class?"); + + // Look up the member of the trait type. + S.LookupQualifiedName(TraitMemberLookup, RD); + return TraitMemberLookup.isAmbiguous(); +} + +static TemplateArgumentLoc +getTrivialIntegralTemplateArgument(Sema &S, SourceLocation Loc, QualType T, + uint64_t I) { + TemplateArgument Arg(S.Context, S.Context.MakeIntValue(I, T), T); + return S.getTrivialTemplateArgumentLoc(Arg, T, Loc); +} + +static TemplateArgumentLoc +getTrivialTypeTemplateArgument(Sema &S, SourceLocation Loc, QualType T) { + return S.getTrivialTemplateArgumentLoc(TemplateArgument(T), QualType(), Loc); +} + +namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; } + +static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, + llvm::APSInt &Size) { + EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated); + + DeclarationName Value = S.PP.getIdentifierInfo("value"); + LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName); + + // Form template argument list for tuple_size. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); + + // If there's no tuple_size specialization, it's not tuple-like. + if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0)) + return IsTupleLike::NotTupleLike; + + // FIXME: According to the standard, we're not supposed to diagnose if any + // of the steps below fail (or if lookup for ::value is ambiguous or otherwise + // results in an error), but this is subject to a pending CWG issue / NB + // comment, which says we do diagnose if tuple_size is complete but + // tuple_size::value is not an ICE. + + struct ICEDiagnoser : Sema::VerifyICEDiagnoser { + LookupResult &R; + TemplateArgumentListInfo &Args; + ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args) + : R(R), Args(Args) {} + void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) { + S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) + << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + } + } Diagnoser(R, Args); + + if (R.empty()) { + Diagnoser.diagnoseNotICE(S, Loc, SourceRange()); + return IsTupleLike::Error; + } + + ExprResult E = + S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false); + if (E.isInvalid()) + return IsTupleLike::Error; + + E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false); + if (E.isInvalid()) + return IsTupleLike::Error; + + return IsTupleLike::TupleLike; +} + +/// \return std::tuple_element::type. +static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, + unsigned I, QualType T) { + // Form template argument list for tuple_element. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument( + getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I)); + Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); + + DeclarationName TypeDN = S.PP.getIdentifierInfo("type"); + LookupResult R(S, TypeDN, Loc, Sema::LookupOrdinaryName); + if (lookupStdTypeTraitMember( + S, R, Loc, "tuple_element", Args, + diag::err_decomp_decl_std_tuple_element_not_specialized)) + return QualType(); + + auto *TD = R.getAsSingle(); + if (!TD) { + R.suppressDiagnostics(); + S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized) + << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + if (!R.empty()) + S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); + return QualType(); + } + + return S.Context.getTypeDeclType(TD); +} + +namespace { +struct BindingDiagnosticTrap { + Sema &S; + DiagnosticErrorTrap Trap; + BindingDecl *BD; + + BindingDiagnosticTrap(Sema &S, BindingDecl *BD) + : S(S), Trap(S.Diags), BD(BD) {} + ~BindingDiagnosticTrap() { + if (Trap.hasErrorOccurred()) + S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD; + } +}; +} + +static bool checkTupleLikeDecomposition(Sema &S, + ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + llvm::APSInt TupleSize) { + if ((int64_t)Bindings.size() != TupleSize) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10) + << (TupleSize < Bindings.size()); + return true; + } + + if (Bindings.empty()) + return false; + + DeclarationName GetDN = S.PP.getIdentifierInfo("get"); + + // [dcl.decomp]p3: + // The unqualified-id get is looked up in the scope of E by class member + // access lookup + LookupResult MemberGet(S, GetDN, Src->getLocation(), Sema::LookupMemberName); + bool UseMemberGet = false; + if (S.isCompleteType(Src->getLocation(), DecompType)) { + if (auto *RD = DecompType->getAsCXXRecordDecl()) + S.LookupQualifiedName(MemberGet, RD); + if (MemberGet.isAmbiguous()) + return true; + UseMemberGet = !MemberGet.empty(); + S.FilterAcceptableTemplateNames(MemberGet); + } + + unsigned I = 0; + for (auto *B : Bindings) { + BindingDiagnosticTrap Trap(S, B); + SourceLocation Loc = B->getLocation(); + + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + + // e is an lvalue if the type of the entity is an lvalue reference and + // an xvalue otherwise + if (!Src->getType()->isLValueReferenceType()) + E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp, + E.get(), nullptr, VK_XValue); + + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument( + getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I)); + + if (UseMemberGet) { + // if [lookup of member get] finds at least one declaration, the + // initializer is e.get(). + E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false, + CXXScopeSpec(), SourceLocation(), nullptr, + MemberGet, &Args, nullptr); + if (E.isInvalid()) + return true; + + E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc); + } else { + // Otherwise, the initializer is get(e), where get is looked up + // in the associated namespaces. + Expr *Get = UnresolvedLookupExpr::Create( + S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(), + DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args, + UnresolvedSetIterator(), UnresolvedSetIterator()); + + Expr *Arg = E.get(); + E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc); + } + if (E.isInvalid()) + return true; + Expr *Init = E.get(); + + // Given the type T designated by std::tuple_element::type, + QualType T = getTupleLikeElementType(S, Loc, I, DecompType); + if (T.isNull()) + return true; + + // each vi is a variable of type "reference to T" initialized with the + // initializer, where the reference is an lvalue reference if the + // initializer is an lvalue and an rvalue reference otherwise + QualType RefType = + S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName()); + if (RefType.isNull()) + return true; + + InitializedEntity Entity = InitializedEntity::InitializeBinding(B, RefType); + InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc); + InitializationSequence Seq(S, Entity, Kind, Init); + E = Seq.Perform(S, Entity, Kind, Init); + if (E.isInvalid()) + return true; + + B->setBinding(T, E.get()); + I++; + } + + return false; +} + +/// Find the base class to decompose in a built-in decomposition of a class type. +/// This base class search is, unfortunately, not quite like any other that we +/// perform anywhere else in C++. +static const CXXRecordDecl *findDecomposableBaseClass(Sema &S, + SourceLocation Loc, + const CXXRecordDecl *RD, + CXXCastPath &BasePath) { + auto BaseHasFields = [](const CXXBaseSpecifier *Specifier, + CXXBasePath &Path) { + return Specifier->getType()->getAsCXXRecordDecl()->hasDirectFields(); + }; + + const CXXRecordDecl *ClassWithFields = nullptr; + if (RD->hasDirectFields()) + // [dcl.decomp]p4: + // Otherwise, all of E's non-static data members shall be public direct + // members of E ... + ClassWithFields = RD; + else { + // ... or of ... + CXXBasePaths Paths; + Paths.setOrigin(const_cast(RD)); + if (!RD->lookupInBases(BaseHasFields, Paths)) { + // If no classes have fields, just decompose RD itself. (This will work + // if and only if zero bindings were provided.) + return RD; + } + + CXXBasePath *BestPath = nullptr; + for (auto &P : Paths) { + if (!BestPath) + BestPath = &P; + else if (!S.Context.hasSameType(P.back().Base->getType(), + BestPath->back().Base->getType())) { + // ... the same ... + S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members) + << false << RD << BestPath->back().Base->getType() + << P.back().Base->getType(); + return nullptr; + } else if (P.Access < BestPath->Access) { + BestPath = &P; + } + } + + // ... unambiguous ... + QualType BaseType = BestPath->back().Base->getType(); + if (Paths.isAmbiguous(S.Context.getCanonicalType(BaseType))) { + S.Diag(Loc, diag::err_decomp_decl_ambiguous_base) + << RD << BaseType << S.getAmbiguousPathsDisplayString(Paths); + return nullptr; + } + + // ... public base class of E. + if (BestPath->Access != AS_public) { + S.Diag(Loc, diag::err_decomp_decl_non_public_base) + << RD << BaseType; + for (auto &BS : *BestPath) { + if (BS.Base->getAccessSpecifier() != AS_public) { + S.Diag(BS.Base->getLocStart(), diag::note_access_constrained_by_path) + << (BS.Base->getAccessSpecifier() == AS_protected) + << (BS.Base->getAccessSpecifierAsWritten() == AS_none); + break; + } + } + return nullptr; + } + + ClassWithFields = BaseType->getAsCXXRecordDecl(); + S.BuildBasePathArray(Paths, BasePath); + } + + // The above search did not check whether the selected class itself has base + // classes with fields, so check that now. + CXXBasePaths Paths; + if (ClassWithFields->lookupInBases(BaseHasFields, Paths)) { + S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members) + << (ClassWithFields == RD) << RD << ClassWithFields + << Paths.front().back().Base->getType(); + return nullptr; + } + + return ClassWithFields; +} + +static bool checkMemberDecomposition(Sema &S, ArrayRef Bindings, + ValueDecl *Src, QualType DecompType, + const CXXRecordDecl *RD) { + CXXCastPath BasePath; + RD = findDecomposableBaseClass(S, Src->getLocation(), RD, BasePath); + if (!RD) + return true; + QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD), + DecompType.getQualifiers()); + + auto DiagnoseBadNumberOfBindings = [&]() -> bool { + unsigned NumFields = std::distance(RD->field_begin(), RD->field_end()); + assert(Bindings.size() != NumFields); + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << NumFields + << (NumFields < Bindings.size()); + return true; + }; + + // all of E's non-static data members shall be public [...] members, + // E shall not have an anonymous union member, ... + unsigned I = 0; + for (auto *FD : RD->fields()) { + if (FD->isUnnamedBitfield()) + continue; + + if (FD->isAnonymousStructOrUnion()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) + << DecompType << FD->getType()->isUnionType(); + S.Diag(FD->getLocation(), diag::note_declared_at); + return true; + } + + // We have a real field to bind. + if (I >= Bindings.size()) + return DiagnoseBadNumberOfBindings(); + auto *B = Bindings[I++]; + + SourceLocation Loc = B->getLocation(); + if (FD->getAccess() != AS_public) { + S.Diag(Loc, diag::err_decomp_decl_non_public_member) << FD << DecompType; + + // Determine whether the access specifier was explicit. + bool Implicit = true; + for (const auto *D : RD->decls()) { + if (declaresSameEntity(D, FD)) + break; + if (isa(D)) { + Implicit = false; + break; + } + } + + S.Diag(FD->getLocation(), diag::note_access_natural) + << (FD->getAccess() == AS_protected) << Implicit; + return true; + } + + // Initialize the binding to Src.FD. + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + E = S.ImpCastExprToType(E.get(), BaseType, CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); + if (E.isInvalid()) + return true; + E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc, + CXXScopeSpec(), FD, + DeclAccessPair::make(FD, FD->getAccess()), + DeclarationNameInfo(FD->getDeclName(), Loc)); + if (E.isInvalid()) + return true; + + // If the type of the member is T, the referenced type is cv T, where cv is + // the cv-qualification of the decomposition expression. + // + // FIXME: We resolve a defect here: if the field is mutable, we do not add + // 'const' to the type of the field. + Qualifiers Q = DecompType.getQualifiers(); + if (FD->isMutable()) + Q.removeConst(); + B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get()); + } + + if (I != Bindings.size()) + return DiagnoseBadNumberOfBindings(); + + return false; +} + +void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) { + QualType DecompType = DD->getType(); + + // If the type of the decomposition is dependent, then so is the type of + // each binding. + if (DecompType->isDependentType()) { + for (auto *B : DD->bindings()) + B->setType(Context.DependentTy); + return; + } + + DecompType = DecompType.getNonReferenceType(); + ArrayRef Bindings = DD->bindings(); + + // C++1z [dcl.decomp]/2: + // If E is an array type [...] + // As an extension, we also support decomposition of built-in complex and + // vector types. + if (auto *CAT = Context.getAsConstantArrayType(DecompType)) { + if (checkArrayDecomposition(*this, Bindings, DD, DecompType, CAT)) + DD->setInvalidDecl(); + return; + } + if (auto *VT = DecompType->getAs()) { + if (checkVectorDecomposition(*this, Bindings, DD, DecompType, VT)) + DD->setInvalidDecl(); + return; + } + if (auto *CT = DecompType->getAs()) { + if (checkComplexDecomposition(*this, Bindings, DD, DecompType, CT)) + DD->setInvalidDecl(); + return; + } + + // C++1z [dcl.decomp]/3: + // if the expression std::tuple_size::value is a well-formed integral + // constant expression, [...] + llvm::APSInt TupleSize(32); + switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) { + case IsTupleLike::Error: + DD->setInvalidDecl(); + return; + + case IsTupleLike::TupleLike: + if (checkTupleLikeDecomposition(*this, Bindings, DD, DecompType, TupleSize)) + DD->setInvalidDecl(); + return; + + case IsTupleLike::NotTupleLike: + break; + } + + // C++1z [dcl.dcl]/8: + // [E shall be of array or non-union class type] + CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl(); + if (!RD || RD->isUnion()) { + Diag(DD->getLocation(), diag::err_decomp_decl_unbindable_type) + << DD << !RD << DecompType; + DD->setInvalidDecl(); + return; + } + + // C++1z [dcl.decomp]/4: + // all of E's non-static data members shall be [...] direct members of + // E or of the same unambiguous public base class of E, ... + if (checkMemberDecomposition(*this, Bindings, DD, DecompType, RD)) + DD->setInvalidDecl(); +} + /// \brief Merge the exception specifications of two variable declarations. /// /// This is called when there's a redeclaration of a VarDecl. The function @@ -912,7 +1657,8 @@ // C++11 and permitted in C++1y, so ignore them. continue; - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { // C++1y [dcl.constexpr]p3 allows anything except: // a definition of a variable of non-literal type or of static or // thread storage duration or for which no initialization is performed. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1788,6 +1788,12 @@ E->setObjectKind(OK_BitField); } + // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier + // designates a bit-field. + if (auto *BD = dyn_cast(D)) + if (auto *BE = BD->getBinding()) + E->setObjectKind(BE->getObjectKind()); + return E; } @@ -2943,7 +2949,6 @@ case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: case Decl::Decomposition: - case Decl::Binding: case Decl::OMPCapturedExpr: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && @@ -2971,6 +2976,14 @@ break; } + + case Decl::Binding: { + // These are always lvalues. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + // FIXME: Adjust cv-qualifiers for capture. + break; + } case Decl::Function: { if (unsigned BID = cast(VD)->getBuiltinID()) { @@ -6009,7 +6022,9 @@ CheckTollFreeBridgeCast(castType, CastExpr); CheckObjCBridgeRelatedCast(castType, CastExpr); - + + DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } @@ -8669,11 +8684,10 @@ << RHS.get()->getSourceRange(); } -/// \brief Return the resulting type when an OpenCL vector is shifted +/// \brief Return the resulting type when a vector is shifted /// by a scalar or vector shift amount. -static QualType checkOpenCLVectorShift(Sema &S, - ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, bool IsCompAssign) { +static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign) { // OpenCL v1.1 s6.3.j says RHS can be a vector only if LHS is a vector. if (!LHS.get()->getType()->isVectorType()) { S.Diag(Loc, diag::err_shift_rhs_only_vector) @@ -8741,11 +8755,9 @@ // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - if (LangOpts.OpenCL) - return checkOpenCLVectorShift(*this, LHS, RHS, Loc, IsCompAssign); if (LangOpts.ZVector) { // The shift operators for the z vector extensions work basically - // like OpenCL shifts, except that neither the LHS nor the RHS is + // like general shifts, except that neither the LHS nor the RHS is // allowed to be a "vector bool". if (auto LHSVecType = LHS.get()->getType()->getAs()) if (LHSVecType->getVectorKind() == VectorType::AltiVecBool) @@ -8753,11 +8765,8 @@ if (auto RHSVecType = RHS.get()->getType()->getAs()) if (RHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); - return checkOpenCLVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } - return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } // Shifts don't perform usual arithmetic conversions, they just do integer @@ -10580,7 +10589,8 @@ return MPTy; } } - } else if (!isa(dcl) && !isa(dcl)) + } else if (!isa(dcl) && !isa(dcl) && + !isa(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } @@ -10600,6 +10610,8 @@ if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + CheckAddressOfPackedMember(op); + return Context.getPointerType(op->getType()); } Index: lib/Sema/SemaExprMember.cpp =================================================================== --- lib/Sema/SemaExprMember.cpp +++ lib/Sema/SemaExprMember.cpp @@ -771,12 +771,6 @@ false, ExtraArgs); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo); - ExprResult Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, SourceLocation loc, @@ -862,7 +856,7 @@ // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, + result = BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), EmptySS, field, foundDecl, memberNameInfo).get(); if (!result) @@ -883,9 +877,10 @@ DeclAccessPair::make(field, field->getAccess()); result = - BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, - SourceLocation(), (FI == FEnd ? SS : EmptySS), - field, fakeFoundDecl, memberNameInfo).get(); + BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(), + (FI == FEnd ? SS : EmptySS), field, + fakeFoundDecl, memberNameInfo) + .get(); } return result; @@ -1153,8 +1148,8 @@ return ExprError(); if (FieldDecl *FD = dyn_cast(MemberDecl)) - return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD, - FoundDecl, MemberNameInfo); + return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl, + MemberNameInfo); if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, @@ -1757,11 +1752,11 @@ NameInfo, TemplateArgs, S, &ExtraArgs); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { +ExprResult +Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, + SourceLocation OpLoc, const CXXScopeSpec &SS, + FieldDecl *Field, DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo) { // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note // that *x is always an l-value), except that if the base isn't @@ -1795,36 +1790,34 @@ // except that 'mutable' members don't pick up 'const'. if (Field->isMutable()) BaseQuals.removeConst(); - Qualifiers MemberQuals - = S.Context.getCanonicalType(MemberType).getQualifiers(); + Qualifiers MemberQuals = + Context.getCanonicalType(MemberType).getQualifiers(); assert(!MemberQuals.hasAddressSpace()); - Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) - MemberType = S.Context.getQualifiedType(MemberType, Combined); + MemberType = Context.getQualifiedType(MemberType, Combined); } - S.UnusedPrivateFields.remove(Field); + UnusedPrivateFields.remove(Field); - ExprResult Base = - S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); + ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), + FoundDecl, Field); if (Base.isInvalid()) return ExprError(); MemberExpr *ME = - BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS, + BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, MemberNameInfo, MemberType, VK, OK); // Build a reference to a private copy for non-static data members in // non-static member functions, privatized by OpenMP constructs. - if (S.getLangOpts().OpenMP && IsArrow && - !S.CurContext->isDependentContext() && + if (getLangOpts().OpenMP && IsArrow && + !CurContext->isDependentContext() && isa(Base.get()->IgnoreParenImpCasts())) { - if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field)) - return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); + if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) + return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); } return ME; } Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -936,6 +936,7 @@ case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_Binding: llvm_unreachable("unexpected braced scalar init"); } @@ -2895,6 +2896,7 @@ case EK_Variable: case EK_Member: + case EK_Binding: return VariableOrMember->getDeclName(); case EK_LambdaCapture: @@ -2918,10 +2920,11 @@ llvm_unreachable("Invalid EntityKind!"); } -DeclaratorDecl *InitializedEntity::getDecl() const { +ValueDecl *InitializedEntity::getDecl() const { switch (getKind()) { case EK_Variable: case EK_Member: + case EK_Binding: return VariableOrMember; case EK_Parameter: @@ -2957,6 +2960,7 @@ case EK_Parameter: case EK_Parameter_CF_Audited: case EK_Member: + case EK_Binding: case EK_New: case EK_Temporary: case EK_CompoundLiteralInit: @@ -2988,6 +2992,7 @@ case EK_Result: OS << "Result"; break; case EK_Exception: OS << "Exception"; break; case EK_Member: OS << "Member"; break; + case EK_Binding: OS << "Binding"; break; case EK_New: OS << "New"; break; case EK_Temporary: OS << "Temporary"; break; case EK_CompoundLiteralInit: OS << "CompoundLiteral";break; @@ -3004,9 +3009,9 @@ break; } - if (Decl *D = getDecl()) { + if (auto *D = getDecl()) { OS << " "; - cast(D)->printQualifiedName(OS); + D->printQualifiedName(OS); } OS << " '" << getType().getAsString() << "'\n"; @@ -5270,6 +5275,7 @@ return Sema::AA_Casting; case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: @@ -5305,6 +5311,7 @@ case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_RelatedResult: + case InitializedEntity::EK_Binding: return true; } @@ -5326,6 +5333,7 @@ return false; case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: @@ -5395,6 +5403,7 @@ return Entity.getThrowLoc(); case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Binding: return Entity.getDecl()->getLocation(); case InitializedEntity::EK_LambdaCapture: @@ -5826,6 +5835,7 @@ case InitializedEntity::EK_Result: case InitializedEntity::EK_Exception: case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: @@ -5875,6 +5885,11 @@ // ctor-initializer persists until the constructor exits. return Entity; + case InitializedEntity::EK_Binding: + // Per [dcl.decomp]p3, the binding is treated as a variable of reference + // type. + return Entity; + case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: // -- A temporary bound to a reference parameter in a function call @@ -6250,7 +6265,7 @@ SourceRange Brackets; // Scavange the location of the brackets from the entity, if we can. - if (DeclaratorDecl *DD = Entity.getDecl()) { + if (auto *DD = dyn_cast_or_null(Entity.getDecl())) { if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) { TypeLoc TL = TInfo->getTypeLoc(); if (IncompleteArrayTypeLoc ArrayLoc = @@ -6645,12 +6660,16 @@ getAssignmentAction(Entity), CCK); if (CurInitExprRes.isInvalid()) return ExprError(); + + S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), CurInit.get()); + CurInit = CurInitExprRes; if (Step->Kind == SK_ConversionSequenceNoNarrowing && S.getLangOpts().CPlusPlus && !CurInit.get()->isValueDependent()) DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, Entity.getType(), CurInit.get()); + break; } Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -5974,8 +5974,12 @@ SmallVector ConvertedArgs; bool InitializationFailed = false; + // Ignore any variadic arguments. Converting them is pointless, since the + // user can't refer to them in the enable_if condition. + unsigned ArgSizeNoVarargs = std::min(Function->param_size(), Args.size()); + // Convert the arguments. - for (unsigned I = 0, E = Args.size(); I != E; ++I) { + for (unsigned I = 0; I != ArgSizeNoVarargs; ++I) { ExprResult R; if (I == 0 && !MissingImplicitThis && isa(Function) && !cast(Function)->isStatic() && Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -2073,11 +2073,8 @@ for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned()); I < NumArgs; ++I) { TemplateArgument TA(Context, I, ArgTy); - Expr *E = SemaRef.BuildExpressionFromIntegralTemplateArgument( - TA, TemplateArgs[2].getLocation()) - .getAs(); - SyntheticTemplateArgs.addArgument( - TemplateArgumentLoc(TemplateArgument(E), E)); + SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc( + TA, ArgTy, TemplateArgs[2].getLocation())); } // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -863,12 +863,12 @@ if (ParamQs == ArgQs) return false; - + // Mismatched (but not missing) Objective-C GC attributes. - if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && + if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && ParamQs.hasObjCGCAttr()) return true; - + // Mismatched (but not missing) address spaces. if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() && ParamQs.hasAddressSpace()) @@ -878,7 +878,7 @@ if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() && ParamQs.hasObjCLifetime()) return true; - + // CVR qualifier superset. return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) @@ -1060,7 +1060,7 @@ // Just skip any attempts to deduce from a placeholder type. if (Arg->isPlaceholderType()) return Sema::TDK_Success; - + unsigned Index = TemplateTypeParm->getIndex(); bool RecanonicalizeArg = false; @@ -1100,7 +1100,7 @@ DeducedQs.removeAddressSpace(); if (ParamQs.hasObjCLifetime()) DeducedQs.removeObjCLifetime(); - + // Objective-C ARC: // If template deduction would produce a lifetime qualifier on a type // that is not a lifetime type, template argument deduction fails. @@ -1109,9 +1109,9 @@ Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_Underqualified; + return Sema::TDK_Underqualified; } - + // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -1119,10 +1119,10 @@ DeducedType->isObjCLifetimeType() && !DeducedQs.hasObjCLifetime()) DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); - + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); - + if (RecanonicalizeArg) DeducedType = S.Context.getCanonicalType(DeducedType); @@ -1163,7 +1163,7 @@ if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; } - + // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { if (!(TDF & TDF_SkipNonDependent)) { @@ -1193,7 +1193,7 @@ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); #define TYPE(Class, Base) #include "clang/AST/TypeNodes.def" - + case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: llvm_unreachable("Type nodes handled above"); @@ -1211,20 +1211,20 @@ case Type::ObjCObjectPointer: { if (TDF & TDF_SkipNonDependent) return Sema::TDK_Success; - + if (TDF & TDF_IgnoreQualifiers) { Param = Param.getUnqualifiedType(); Arg = Arg.getUnqualifiedType(); } - + return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; } - - // _Complex T [placeholder extension] + + // _Complex T [placeholder extension] case Type::Complex: if (const ComplexType *ComplexArg = Arg->getAs()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getElementType(), + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getElementType(), ComplexArg->getElementType(), Info, Deduced, TDF); @@ -1549,7 +1549,7 @@ return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, QualType(MemPtrParam->getClass(), 0), QualType(MemPtrArg->getClass(), 0), - Info, Deduced, + Info, Deduced, TDF & TDF_IgnoreQualifiers); } @@ -1580,15 +1580,15 @@ // Make sure that the vectors have the same number of elements. if (VectorParam->getNumElements() != VectorArg->getNumElements()) return Sema::TDK_NonDeducedMismatch; - + // Perform deduction on the element types. return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, VectorParam->getElementType(), VectorArg->getElementType(), Info, Deduced, TDF); } - - if (const DependentSizedExtVectorType *VectorArg + + if (const DependentSizedExtVectorType *VectorArg = dyn_cast(Arg)) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial @@ -1600,10 +1600,10 @@ VectorArg->getElementType(), Info, Deduced, TDF); } - + return Sema::TDK_NonDeducedMismatch; } - + // (clang extension) // // T __attribute__(((ext_vector_type(N)))) @@ -1619,7 +1619,7 @@ VectorArg->getElementType(), Info, Deduced, TDF)) return Result; - + // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); @@ -1631,8 +1631,8 @@ return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy, false, Info, Deduced); } - - if (const DependentSizedExtVectorType *VectorArg + + if (const DependentSizedExtVectorType *VectorArg = dyn_cast(Arg)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result @@ -1641,20 +1641,20 @@ VectorArg->getElementType(), Info, Deduced, TDF)) return Result; - + // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - + return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(), Info, Deduced); } - + return Sema::TDK_NonDeducedMismatch; } - + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: @@ -1991,8 +1991,6 @@ /// \brief Allocate a TemplateArgumentLoc where all locations have /// been initialized to the given location. /// -/// \param S The semantic analysis object. -/// /// \param Arg The template argument we are producing template argument /// location information for. /// @@ -2002,37 +2000,33 @@ /// /// \param Loc The source location to use for the resulting template /// argument. -static TemplateArgumentLoc -getTrivialTemplateArgumentLoc(Sema &S, - const TemplateArgument &Arg, - QualType NTTPType, - SourceLocation Loc) { +TemplateArgumentLoc +Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, + QualType NTTPType, SourceLocation Loc) { switch (Arg.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't get a NULL template argument here"); case TemplateArgument::Type: - return TemplateArgumentLoc(Arg, - S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + return TemplateArgumentLoc( + Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); case TemplateArgument::Declaration: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .getAs(); + Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .getAs(); return TemplateArgumentLoc(TemplateArgument(E), E); } case TemplateArgument::NullPtr: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .getAs(); + Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .getAs(); return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true), E); } case TemplateArgument::Integral: { - Expr *E - = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs(); + Expr *E = + BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs(); return TemplateArgumentLoc(TemplateArgument(E), E); } @@ -2041,18 +2035,16 @@ NestedNameSpecifierLocBuilder Builder; TemplateName Template = Arg.getAsTemplate(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) - Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc); + Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc); - + Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); + if (Arg.getKind() == TemplateArgument::Template) - return TemplateArgumentLoc(Arg, - Builder.getWithLocInContext(S.Context), + return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context), Loc); - - - return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context), + + return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context), Loc, Loc); } @@ -2100,7 +2092,7 @@ // argument that we can check, almost as if the user had written // the template argument explicitly. TemplateArgumentLoc ArgLoc = - getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation()); + S.getTrivialTemplateArgumentLoc(Arg, NTTPType, Info.getLocation()); // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( @@ -2573,15 +2565,15 @@ ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } - + // Instantiate the return type. QualType ResultType; { // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or + // and the end of the function-definition, member-declarator, or // declarator. unsigned ThisTypeQuals = 0; CXXRecordDecl *ThisContext = nullptr; @@ -2589,7 +2581,7 @@ ThisContext = Method->getParent(); ThisTypeQuals = Method->getTypeQualifiers(); } - + CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, getLangOpts().CPlusPlus11); @@ -2645,35 +2637,35 @@ /// \brief Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. -static bool -CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, +static bool +CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, QualType DeducedA) { ASTContext &Context = S.Context; - + QualType A = OriginalArg.OriginalArgType; QualType OriginalParamType = OriginalArg.OriginalParamType; - + // Check for type equality (top-level cv-qualifiers are ignored). if (Context.hasSameUnqualifiedType(A, DeducedA)) return false; - + // Strip off references on the argument types; they aren't needed for // the following checks. if (const ReferenceType *DeducedARef = DeducedA->getAs()) DeducedA = DeducedARef->getPointeeType(); if (const ReferenceType *ARef = A->getAs()) A = ARef->getPointeeType(); - + // C++ [temp.deduct.call]p4: // [...] However, there are three cases that allow a difference: - // - If the original P is a reference type, the deduced A (i.e., the - // type referred to by the reference) can be more cv-qualified than + // - If the original P is a reference type, the deduced A (i.e., the + // type referred to by the reference) can be more cv-qualified than // the transformed A. if (const ReferenceType *OriginalParamRef = OriginalParamType->getAs()) { // We don't want to keep the reference around any more. OriginalParamType = OriginalParamRef->getPointeeType(); - + Qualifiers AQuals = A.getQualifiers(); Qualifiers DeducedAQuals = DeducedA.getQualifiers(); @@ -2693,16 +2685,16 @@ // Qualifiers match; there's nothing to do. } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { return true; - } else { + } else { // Qualifiers are compatible, so have the argument type adopt the // deduced argument type's qualifiers as if we had performed the // qualification conversion. A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals); } } - - // - The transformed A can be another pointer or pointer to member - // type that can be converted to the deduced A via a qualification + + // - The transformed A can be another pointer or pointer to member + // type that can be converted to the deduced A via a qualification // conversion. // // Also allow conversions which merely strip [[noreturn]] from function types @@ -2715,12 +2707,12 @@ ObjCLifetimeConversion) || S.IsNoReturnConversion(A, DeducedA, ResultTy))) return false; - - - // - If P is a class and P has the form simple-template-id, then the + + + // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. [...] - // [...] Likewise, if P is a pointer to a class of the form - // simple-template-id, the transformed A can be a pointer to a + // [...] Likewise, if P is a pointer to a class of the form + // simple-template-id, the transformed A can be a pointer to a // derived class pointed to by the deduced A. if (const PointerType *OriginalParamPtr = OriginalParamType->getAs()) { @@ -2734,14 +2726,14 @@ } } } - + if (Context.hasSameUnqualifiedType(A, DeducedA)) return false; - + if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && S.IsDerivedFrom(SourceLocation(), A, DeducedA)) return false; - + return true; } @@ -2927,15 +2919,15 @@ if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument - // values that will make the deduced A identical to A (after the type A + // values that will make the deduced A identical to A (after the type A // is transformed as described above). [...] for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) { OriginalCallArg OriginalArg = (*OriginalCallArgs)[I]; unsigned ParamIdx = OriginalArg.ArgIdx; - + if (ParamIdx >= Specialization->getNumParams()) continue; - + QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { Info.FirstArg = TemplateArgument(DeducedA); @@ -2945,7 +2937,7 @@ } } } - + // If we suppressed any diagnostics while performing template argument // deduction, and if we haven't already instantiated this declaration, // keep track of these diagnostics. They'll be emitted if this specialization @@ -3025,7 +3017,7 @@ return QualType(); } - + // Gather the explicit template arguments, if any. TemplateArgumentListInfo ExplicitTemplateArgs; if (Ovl->hasExplicitTemplateArgs()) @@ -3041,14 +3033,14 @@ // non-deduced context. if (!Ovl->hasExplicitTemplateArgs()) return QualType(); - - // Otherwise, see if we can resolve a function type + + // Otherwise, see if we can resolve a function type FunctionDecl *Specialization = nullptr; TemplateDeductionInfo Info(Ovl->getNameLoc()); if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs, Specialization, Info)) continue; - + D = Specialization; } @@ -3291,7 +3283,7 @@ // For all other cases, just match by type. QualType ArgType = Arg->getType(); - if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType, + if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType, ArgType, Arg, TDF)) { Info.Expression = Arg; return Sema::TDK_FailedOverloadResolution; @@ -3382,7 +3374,7 @@ ParamIdx != NumParamTypes; ++ParamIdx) { QualType OrigParamType = ParamTypes[ParamIdx]; QualType ParamType = OrigParamType; - + const PackExpansionType *ParamExpansion = dyn_cast(ParamType); if (!ParamExpansion) { @@ -3392,7 +3384,7 @@ Expr *Arg = Args[ArgIdx++]; QualType ArgType = Arg->getType(); - + unsigned TDF = 0; if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, ParamType, ArgType, Arg, @@ -3419,7 +3411,7 @@ // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, ArgType)); if (TemplateDeductionResult Result @@ -3482,7 +3474,7 @@ // Keep track of the argument type and corresponding argument index, // so we can check for compatibility between the deduced A and A. if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, ArgType)); if (TemplateDeductionResult Result @@ -3643,70 +3635,70 @@ return TDK_Success; } -/// \brief Given a function declaration (e.g. a generic lambda conversion -/// function) that contains an 'auto' in its result type, substitute it +/// \brief Given a function declaration (e.g. a generic lambda conversion +/// function) that contains an 'auto' in its result type, substitute it /// with TypeToReplaceAutoWith. Be careful to pass in the type you want /// to replace 'auto' with and not the actual result type you want /// to set the function to. -static inline void -SubstAutoWithinFunctionReturnType(FunctionDecl *F, +static inline void +SubstAutoWithinFunctionReturnType(FunctionDecl *F, QualType TypeToReplaceAutoWith, Sema &S) { assert(!TypeToReplaceAutoWith->getContainedAutoType()); QualType AutoResultType = F->getReturnType(); - assert(AutoResultType->getContainedAutoType()); - QualType DeducedResultType = S.SubstAutoType(AutoResultType, + assert(AutoResultType->getContainedAutoType()); + QualType DeducedResultType = S.SubstAutoType(AutoResultType, TypeToReplaceAutoWith); S.Context.adjustDeducedFunctionResultType(F, DeducedResultType); } -/// \brief Given a specialized conversion operator of a generic lambda -/// create the corresponding specializations of the call operator and -/// the static-invoker. If the return type of the call operator is auto, -/// deduce its return type and check if that matches the +/// \brief Given a specialized conversion operator of a generic lambda +/// create the corresponding specializations of the call operator and +/// the static-invoker. If the return type of the call operator is auto, +/// deduce its return type and check if that matches the /// return type of the destination function ptr. -static inline Sema::TemplateDeductionResult +static inline Sema::TemplateDeductionResult SpecializeCorrespondingLambdaCallOperatorAndInvoker( CXXConversionDecl *ConversionSpecialized, SmallVectorImpl &DeducedArguments, QualType ReturnTypeOfDestFunctionPtr, TemplateDeductionInfo &TDInfo, Sema &S) { - + CXXRecordDecl *LambdaClass = ConversionSpecialized->getParent(); - assert(LambdaClass && LambdaClass->isGenericLambda()); - + assert(LambdaClass && LambdaClass->isGenericLambda()); + CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator(); QualType CallOpResultType = CallOpGeneric->getReturnType(); - const bool GenericLambdaCallOperatorHasDeducedReturnType = + const bool GenericLambdaCallOperatorHasDeducedReturnType = CallOpResultType->getContainedAutoType(); - - FunctionTemplateDecl *CallOpTemplate = + + FunctionTemplateDecl *CallOpTemplate = CallOpGeneric->getDescribedFunctionTemplate(); FunctionDecl *CallOpSpecialized = nullptr; - // Use the deduced arguments of the conversion function, to specialize our + // Use the deduced arguments of the conversion function, to specialize our // generic lambda's call operator. if (Sema::TemplateDeductionResult Result - = S.FinishTemplateArgumentDeduction(CallOpTemplate, - DeducedArguments, + = S.FinishTemplateArgumentDeduction(CallOpTemplate, + DeducedArguments, 0, CallOpSpecialized, TDInfo)) return Result; - + // If we need to deduce the return type, do so (instantiates the callop). if (GenericLambdaCallOperatorHasDeducedReturnType && CallOpSpecialized->getReturnType()->isUndeducedType()) - S.DeduceReturnType(CallOpSpecialized, + S.DeduceReturnType(CallOpSpecialized, CallOpSpecialized->getPointOfInstantiation(), /*Diagnose*/ true); - + // Check to see if the return type of the destination ptr-to-function // matches the return type of the call operator. if (!S.Context.hasSameType(CallOpSpecialized->getReturnType(), ReturnTypeOfDestFunctionPtr)) return Sema::TDK_NonDeducedMismatch; // Since we have succeeded in matching the source and destination - // ptr-to-functions (now including return type), and have successfully + // ptr-to-functions (now including return type), and have successfully // specialized our corresponding call operator, we are ready to // specialize the static invoker with the deduced arguments of our // ptr-to-function. @@ -3717,16 +3709,16 @@ #ifndef NDEBUG Sema::TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result = #endif - S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0, + S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0, InvokerSpecialized, TDInfo); - assert(Result == Sema::TDK_Success && + assert(Result == Sema::TDK_Success && "If the call operator succeeded so should the invoker!"); // Set the result type to match the corresponding call operator // specialization's result type. if (GenericLambdaCallOperatorHasDeducedReturnType && InvokerSpecialized->getReturnType()->isUndeducedType()) { // Be sure to get the type to replace 'auto' with and not - // the full result type of the call op specialization + // the full result type of the call op specialization // to substitute into the 'auto' of the invoker and conversion // function. // For e.g. @@ -3738,14 +3730,14 @@ ->getDeducedType(); SubstAutoWithinFunctionReturnType(InvokerSpecialized, TypeToReplaceAutoWith, S); - SubstAutoWithinFunctionReturnType(ConversionSpecialized, + SubstAutoWithinFunctionReturnType(ConversionSpecialized, TypeToReplaceAutoWith, S); } - + // Ensure that static invoker doesn't have a const qualifier. - // FIXME: When creating the InvokerTemplate in SemaLambda.cpp + // FIXME: When creating the InvokerTemplate in SemaLambda.cpp // do not use the CallOperator's TypeSourceInfo which allows - // the const qualifier to leak through. + // the const qualifier to leak through. const FunctionProtoType *InvokerFPT = InvokerSpecialized-> getType().getTypePtr()->castAs(); FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo(); @@ -3857,7 +3849,7 @@ // Finish template argument deduction. FunctionDecl *ConversionSpecialized = nullptr; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, ConversionSpecialized, Info); Specialization = cast_or_null(ConversionSpecialized); @@ -3866,19 +3858,19 @@ // function to specialize the corresponding call operator. // e.g., int (*fp)(int) = [](auto a) { return a; }; if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) { - + // Get the return type of the destination ptr-to-function we are converting - // to. This is necessary for matching the lambda call operator's return + // to. This is necessary for matching the lambda call operator's return // type to that of the destination ptr-to-function's return type. - assert(A->isPointerType() && + assert(A->isPointerType() && "Can only convert from lambda to ptr-to-function"); - const FunctionType *ToFunType = + const FunctionType *ToFunType = A->getPointeeType().getTypePtr()->getAs(); const QualType DestFunctionPtrReturnType = ToFunType->getReturnType(); - // Create the corresponding specializations of the call operator and - // the static-invoker; and if the return type is auto, - // deduce the return type and check if it matches the + // Create the corresponding specializations of the call operator and + // the static-invoker; and if the return type is auto, + // deduce the return type and check if it matches the // DestFunctionPtrReturnType. // For instance: // auto L = [](auto a) { return f(a); }; @@ -3886,7 +3878,7 @@ // char (*fp2)(int) = L; <-- Not OK. Result = SpecializeCorrespondingLambdaCallOperatorAndInvoker( - Specialization, Deduced, DestFunctionPtrReturnType, + Specialization, Deduced, DestFunctionPtrReturnType, Info, *this); } return Result; @@ -4103,13 +4095,13 @@ return DAR_Succeeded; } -QualType Sema::SubstAutoType(QualType TypeWithAuto, +QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { return SubstituteAutoTransform(*this, TypeToReplaceAuto). TransformType(TypeWithAuto); } -TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, +TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { return SubstituteAutoTransform(*this, TypeToReplaceAuto). TransformType(TypeWithAuto); @@ -5054,7 +5046,7 @@ TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); llvm::SmallBitVector Deduced(TemplateParams->size()); - ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(), + ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(), Deduced); return Deduced.any(); Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" @@ -599,13 +600,27 @@ } Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) { - return BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier()); + auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD); + return NewBD; } Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) { - // FIXME: Instantiate bindings and pass them in. - return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false); + // Transform the bindings first. + SmallVector NewBindings; + for (auto *OldBD : D->bindings()) + NewBindings.push_back(cast(VisitBindingDecl(OldBD))); + ArrayRef NewBindingArray = NewBindings; + + auto *NewDD = cast_or_null( + VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray)); + + if (!NewDD || NewDD->isInvalidDecl()) + for (auto *NewBD : NewBindings) + NewBD->setInvalidDecl(); + + return NewDD; } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { @@ -613,7 +628,8 @@ } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, - bool InstantiatingVarTemplate) { + bool InstantiatingVarTemplate, + ArrayRef *Bindings) { // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), @@ -634,9 +650,15 @@ SemaRef.adjustContextForLocalExternDecl(DC); // Build the instantiated declaration. - VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), - D->getLocation(), D->getIdentifier(), - DI->getType(), DI, D->getStorageClass()); + VarDecl *Var; + if (Bindings) + Var = DecompositionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), + D->getLocation(), DI->getType(), DI, + D->getStorageClass(), *Bindings); + else + Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), + D->getLocation(), D->getIdentifier(), DI->getType(), + DI, D->getStorageClass()); // In ARC, infer 'retaining' for variables of retainable type. if (SemaRef.getLangOpts().ObjCAutoRefCount && Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -1748,6 +1748,12 @@ if (T.isNull()) return QualType(); + // Ignore any attempt to form a cv-qualified reference. + if (T->isReferenceType()) { + Qs.removeConst(); + Qs.removeVolatile(); + } + // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { @@ -1789,6 +1795,11 @@ if (T.isNull()) return QualType(); + // Ignore any attempt to form a cv-qualified reference. + if (T->isReferenceType()) + CVRAU &= + ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic); + // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and // TQ_unaligned; unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -312,6 +312,8 @@ void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); } void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); + void VisitDecompositionDecl(DecompositionDecl *DD); + void VisitBindingDecl(BindingDecl *BD); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); DeclID VisitTemplateDecl(TemplateDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); @@ -1295,6 +1297,18 @@ // inheritance of default arguments. } +void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) { + VisitVarDecl(DD); + BindingDecl **BDs = DD->getTrailingObjects(); + for (unsigned I = 0; I != DD->NumBindings; ++I) + BDs[I] = ReadDeclAs(Record, Idx); +} + +void ASTDeclReader::VisitBindingDecl(BindingDecl *BD) { + VisitValueDecl(BD); + BD->Binding = Reader.ReadExpr(F); +} + void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast(Reader.ReadExpr(F))); @@ -3400,6 +3414,12 @@ case DECL_PARM_VAR: D = ParmVarDecl::CreateDeserialized(Context, ID); break; + case DECL_DECOMPOSITION: + D = DecompositionDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; + case DECL_BINDING: + D = BindingDecl::CreateDeserialized(Context, ID); + break; case DECL_FILE_SCOPE_ASM: D = FileScopeAsmDecl::CreateDeserialized(Context, ID); break; Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -96,6 +96,8 @@ void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); + void VisitDecompositionDecl(DecompositionDecl *D); + void VisitBindingDecl(BindingDecl *D); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); @@ -941,8 +943,7 @@ D->getFirstDecl() == D->getMostRecentDecl() && D->getInitStyle() == VarDecl::CInit && D->getInit() == nullptr && - !isa(D) && - !isa(D) && + D->getKind() == Decl::Var && !D->isInline() && !D->isConstexpr() && !D->isInitCapture() && @@ -1005,6 +1006,22 @@ "PARM_VAR_DECL can't be static data member"); } +void ASTDeclWriter::VisitDecompositionDecl(DecompositionDecl *D) { + // Record the number of bindings first to simplify deserialization. + Record.push_back(D->bindings().size()); + + VisitVarDecl(D); + for (auto *B : D->bindings()) + Record.AddDeclRef(B); + Code = serialization::DECL_DECOMPOSITION; +} + +void ASTDeclWriter::VisitBindingDecl(BindingDecl *D) { + VisitValueDecl(D); + Record.AddStmt(D->getBinding()); + Code = serialization::DECL_BINDING; +} + void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Record.AddStmt(D->getAsmString()); Index: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -1171,8 +1171,9 @@ break; } - // For CoreGraphics ('CG') types. - if (cocoa::isRefType(RetTy, "CG", FName)) { + // For CoreGraphics ('CG') and CoreVideo ('CV') types. + if (cocoa::isRefType(RetTy, "CG", FName) || + cocoa::isRefType(RetTy, "CV", FName)) { if (isRetain(FD, FName)) S = getUnarySummary(FT, cfretain); else @@ -3372,12 +3373,13 @@ // Handle: id NSMakeCollectable(CFTypeRef) canEval = II->isStr("NSMakeCollectable"); } else if (ResultTy->isPointerType()) { - // Handle: (CF|CG)Retain + // Handle: (CF|CG|CV)Retain // CFAutorelease // CFMakeCollectable // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist). if (cocoa::isRefType(ResultTy, "CF", FName) || - cocoa::isRefType(ResultTy, "CG", FName)) { + cocoa::isRefType(ResultTy, "CG", FName) || + cocoa::isRefType(ResultTy, "CV", FName)) { canEval = isRetain(FD, FName) || isAutorelease(FD, FName) || isMakeCollectable(FD, FName); } Index: test/Analysis/copypaste/call.cpp =================================================================== --- test/Analysis/copypaste/call.cpp +++ test/Analysis/copypaste/call.cpp @@ -22,3 +22,15 @@ return b(); return true; } + +// Test that we don't crash on function pointer calls + +bool (*funcPtr)(int); + +bool fooPtr1(int x) { + if (x > 0) + return false; + else if (x < 0) + return funcPtr(1); + return true; +} Index: test/Analysis/retain-release.m =================================================================== --- test/Analysis/retain-release.m +++ test/Analysis/retain-release.m @@ -1247,6 +1247,26 @@ pixelBufferAttributes, pixelBufferOut) ; } +#pragma clang arc_cf_code_audited begin +typedef struct SomeOpaqueStruct *CMSampleBufferRef; +CVImageBufferRef _Nonnull CMSampleBufferGetImageBuffer(CMSampleBufferRef _Nonnull sbuf); +#pragma clang arc_cf_code_audited end + +CVBufferRef _Nullable CVBufferRetain(CVBufferRef _Nullable buffer); +void CVBufferRelease(CF_CONSUMED CVBufferRef _Nullable buffer); + +void testCVPrefixRetain(CMSampleBufferRef sbuf) { + // Make sure RetainCountChecker treats CVFooRetain() as a CF-style retain. + CVPixelBufferRef pixelBuf = CMSampleBufferGetImageBuffer(sbuf); + CVBufferRetain(pixelBuf); + CVBufferRelease(pixelBuf); // no-warning + + + // Make sure result of CVFooRetain() is the same as its argument. + CVPixelBufferRef pixelBufAlias = CVBufferRetain(pixelBuf); + CVBufferRelease(pixelBufAlias); // no-warning +} + //===----------------------------------------------------------------------===// // False leak associated with // CGBitmapContextCreateWithData Index: test/CXX/dcl.decl/dcl.decomp/p2.cpp =================================================================== --- /dev/null +++ test/CXX/dcl.decl/dcl.decomp/p2.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +int array() { + static int arr[3] = {}; + // FIXME: We are supposed to create an array object here and perform elementwise initialization. + auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}} + + auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}} + auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}} + + auto &[r0, r1, r2] = arr; + const auto &[cr0, cr1, cr2] = arr; + + static_assert(&arr[0] == &r0); + static_assert(&arr[0] == &cr0); + + using T = int; + using T = decltype(r0); + using U = const int; + using U = decltype(cr0); + + return r1 + cr2; +} Index: test/CXX/dcl.decl/dcl.decomp/p3.cpp =================================================================== --- /dev/null +++ test/CXX/dcl.decl/dcl.decomp/p3.cpp @@ -0,0 +1,232 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +using size_t = decltype(sizeof(0)); + +struct A { int x, y; }; +struct B { int x, y; }; + +void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise + +namespace std { template struct tuple_size; } +void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise + +struct Bad1 {}; +template<> struct std::tuple_size {}; +void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size::value' is not a valid integral constant expression}} + +struct Bad2 {}; +template<> struct std::tuple_size { const int value = 5; }; +void no_tuple_size_4() { auto [x, y] = Bad2(); } // expected-error {{cannot decompose this type; 'std::tuple_size::value' is not a valid integral constant expression}} + +template<> struct std::tuple_size { static const int value = 3; }; +template<> struct std::tuple_size { enum { value = 3 }; }; + +void no_get_1() { + { + auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}} + auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}} + } + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +int get(A); + +void no_get_2() { + // FIXME: This diagnostic is not great. + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +template float &get(A); + +void no_tuple_element_1() { + auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}, A>::type' does not name a type}} expected-note {{in implicit}} +} + +namespace std { template struct tuple_element; } // expected-note 2{{here}} + +void no_tuple_element_2() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<0, A> { typedef float type; }; + +void no_tuple_element_3() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<1, A> { typedef float &type; }; +template<> struct std::tuple_element<2, A> { typedef const float &type; }; + +template auto get(B) -> int (&)[N + 1]; +template struct std::tuple_element { typedef int type[N +1 ]; }; + +template struct std::tuple_size : std::tuple_size {}; +template struct std::tuple_element { + typedef const typename std::tuple_element::type type; +}; + +void referenced_type() { + auto [a0, a1, a2] = A(); + auto [b0, b1, b2] = B(); + + A a; + B b; + auto &[ar0, ar1, ar2] = a; + auto &[br0, br1, br2] = b; + + auto &&[arr0, arr1, arr2] = A(); + auto &&[brr0, brr1, brr2] = B(); + + const auto &[acr0, acr1, acr2] = A(); + const auto &[bcr0, bcr1, bcr2] = B(); + + + using Float = float; + using Float = decltype(a0); + using Float = decltype(ar0); + using Float = decltype(arr0); + + using ConstFloat = const float; + using ConstFloat = decltype(acr0); + + using FloatRef = float&; + using FloatRef = decltype(a1); + using FloatRef = decltype(ar1); + using FloatRef = decltype(arr1); + using FloatRef = decltype(acr1); + + using ConstFloatRef = const float&; + using ConstFloatRef = decltype(a2); + using ConstFloatRef = decltype(ar2); + using ConstFloatRef = decltype(arr2); + using ConstFloatRef = decltype(acr2); + + + using Int1 = int[1]; + using Int1 = decltype(b0); + using Int1 = decltype(br0); + using Int1 = decltype(brr0); + + using ConstInt1 = const int[1]; + using ConstInt1 = decltype(bcr0); + + using Int2 = int[2]; + using Int2 = decltype(b1); + using Int2 = decltype(br1); + using Int2 = decltype(brr1); + + using ConstInt2 = const int[2]; + using ConstInt2 = decltype(bcr1); + + using Int3 = int[3]; + using Int3 = decltype(b2); + using Int3 = decltype(br2); + using Int3 = decltype(brr2); + + using ConstInt3 = const int[3]; + using ConstInt3 = decltype(bcr2); +} + +struct C { template int get(); }; +template<> struct std::tuple_size { static const int value = 1; }; +template<> struct std::tuple_element<0, C> { typedef int type; }; + +int member_get() { + auto [c] = C(); + using T = int; + using T = decltype(c); + return c; +} + +struct D { template struct get {}; }; // expected-note {{declared here}} +template<> struct std::tuple_size { static const int value = 1; }; +template<> struct std::tuple_element<0, D> { typedef D::get<0> type; }; +void member_get_class_template() { + auto [d] = D(); // expected-error {{cannot refer to member 'get' in 'D' with '.'}} expected-note {{in implicit init}} +} + +struct E { int get(); }; +template<> struct std::tuple_size { static const int value = 1; }; +template<> struct std::tuple_element<0, E> { typedef int type; }; +void member_get_non_template() { + // FIXME: This diagnostic is not very good. + auto [e] = E(); // expected-error {{no member named 'get'}} expected-note {{in implicit init}} +} + +namespace ADL { + struct X {}; +}; +template int get(ADL::X); +template<> struct std::tuple_size { static const int value = 1; }; +template<> struct std::tuple_element<0, ADL::X> { typedef int type; }; +void adl_only_bad() { + auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}} +} + +template +struct wrap { + template GetTypeLV get() &; + template GetTypeRV get() &&; +}; +template +struct std::tuple_size> { + static const int value = 1; +}; +template +struct std::tuple_element<0, wrap> { + using type = ET; +}; + +template T &lvalue(); + +void test_value_category() { + // If the declared variable is an lvalue reference, the operand to get is an + // lvalue. Otherwise it's an xvalue. + { auto [a] = wrap(); } + { auto &[a] = lvalue>(); } + { auto &&[a] = wrap(); } + // If the initializer (call to get) is an lvalue, the binding is an lvalue + // reference to the element type. Otherwise it's an rvalue reference to the + // element type. + { auto [a] = wrap(); } + { auto [a] = wrap(); } + { auto [a] = wrap(); } // ok, reference collapse to int& + + { auto [a] = wrap(); } + { auto [a] = wrap(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}} + { auto [a] = wrap(); } + { auto [a] = wrap(); } + + { auto [a] = wrap(); } // expected-error {{cannot bind}} expected-note {{implicit}} + { auto [a] = wrap(); } // ok, const int &a can bind to float + { auto [a] = wrap(); } // ok, int &&a can bind to float +} + +namespace constant { + struct Q {}; + template constexpr int get(Q &&) { return N * N; } +} +template<> struct std::tuple_size { static const int value = 3; }; +template struct std::tuple_element { typedef int type; }; +namespace constant { + Q q; + // This creates and lifetime-extends a temporary to hold the result of each get() call. + auto [a, b, c] = q; // expected-note {{temporary}} + static_assert(a == 0); // expected-error {{constant expression}} expected-note {{temporary}} + + constexpr bool f() { + auto [a, b, c] = q; + return a == 0 && b == 1 && c == 4; + } + static_assert(f()); + + constexpr int g() { + int *p = nullptr; + { + auto [a, b, c] = q; + p = &c; + } + return *p; // expected-note {{read of object outside its lifetime}} + } + static_assert(g() == 4); // expected-error {{constant}} expected-note {{in call to 'g()'}} +} Index: test/CXX/dcl.decl/dcl.decomp/p4.cpp =================================================================== --- /dev/null +++ test/CXX/dcl.decl/dcl.decomp/p4.cpp @@ -0,0 +1,200 @@ +// RUN: %clang_cc1 -std=c++1z -verify -triple i686-linux-gnu %s + +template struct same; +template struct same { ~same(); }; + +struct Empty {}; + +struct A { + int a; +}; + +namespace NonPublicMembers { + struct NonPublic1 { + protected: + int a; // expected-note {{declared protected here}} + }; + + struct NonPublic2 { + private: + int a; // expected-note 2{{declared private here}} + }; + + struct NonPublic3 : private A {}; // expected-note {{constrained by private inheritance}} + + struct NonPublic4 : NonPublic2 {}; + + void test() { + auto [a1] = NonPublic1(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic1'}} + auto [a2] = NonPublic2(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic2'}} + auto [a3] = NonPublic3(); // expected-error {{cannot decompose members of non-public base class 'A' of 'NonPublic3'}} + auto [a4] = NonPublic4(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic4'}} + } +} + +namespace AnonymousMember { + struct Struct { + struct { // expected-note {{declared here}} + int i; + }; + }; + + struct Union { + union { // expected-note {{declared here}} + int i; + }; + }; + + void test() { + auto [a1] = Struct(); // expected-error {{cannot decompose class type 'AnonymousMember::Struct' because it has an anonymous struct member}} + auto [a2] = Union(); // expected-error {{cannot decompose class type 'AnonymousMember::Union' because it has an anonymous union member}} + } +} + +namespace MultipleClasses { + struct B : A { + int a; + }; + + struct C { int a; }; + struct D : A, C {}; + + struct E : virtual A {}; + struct F : A, E {}; // expected-warning {{direct base 'A' is inaccessible due to ambiguity}} + + struct G : virtual A {}; + struct H : E, G {}; + + struct I { int i; }; + struct J : I {}; + struct K : I, virtual J {}; // expected-warning {{direct base 'MultipleClasses::I' is inaccessible due to ambiguity}} + + struct L : virtual J {}; + struct M : virtual J, L {}; + + void test() { + auto [b] = B(); // expected-error {{cannot decompose class type 'B': both it and its base class 'A' have non-static data members}} + auto [d] = D(); // expected-error {{cannot decompose class type 'D': its base classes 'A' and 'MultipleClasses::C' have non-static data members}} + auto [e] = E(); + auto [f] = F(); // expected-error-re {{cannot decompose members of ambiguous base class 'A' of 'F':{{.*}}struct MultipleClasses::F -> struct A{{.*}}struct MultipleClasses::F -> struct MultipleClasses::E -> struct A}} + auto [h] = H(); // ok, only one (virtual) base subobject even though there are two paths to it + auto [k] = K(); // expected-error {{cannot decompose members of ambiguous base class 'MultipleClasses::I'}} + auto [m] = M(); // ok, all paths to I are through the same virtual base subobject J + + same(); + } +} + +namespace BindingTypes { + struct A { + int i = 0; + int &r = i; + const float f = i; + mutable volatile int mvi; + }; + void e() { + auto [i,r,f,mvi] = A(); + + same(); + same(); + same(); + same(); + + same(); + same(); + same(); + same(); + } + void f() { + auto &&[i,r,f,mvi] = A(); + + same(); + same(); + same(); + same(); + + same(); + same(); + same(); + same(); + } + void g() { + const auto [i,r,f,mvi] = A(); + + same(); + same(); + same(); + same(); // not 'const volatile int', per expected resolution of DRxxx + + same(); + same(); + same(); + same(); // not 'const volatile int&', per expected resolution of DRxxx + } + void h() { + typedef const A CA; + auto &[i,r,f,mvi] = CA(); // type of var is 'const A &' + + same(); // not 'int', per expected resolution of DRxxx + same(); + same(); + same(); // not 'const volatile int', per expected resolution of DRxxx + + same(); // not 'int&', per expected resolution of DRxxx + same(); + same(); + same(); // not 'const volatile int&', per expected resolution of DRxxx + } + struct B { + mutable int i; + }; + void mut() { + auto [i] = B(); + const auto [ci] = B(); + volatile auto [vi] = B(); + same(); + same(); + same(); + } +} + +namespace Bitfield { + struct S { unsigned long long x : 4, y : 32; int z; }; // expected-note 2{{here}} + int f(S s) { + auto [a, b, c] = s; + unsigned long long &ra = a; // expected-error {{bit-field 'x'}} + unsigned long long &rb = b; // expected-error {{bit-field 'y'}} + int &rc = c; + + // the type of the binding is the type of the field + same(); + same(); + + // the type of the expression is an lvalue of the field type + // (even though a reference can't bind to the field) + same(); + same(); + + // the expression promotes to a type large enough to hold the result + same(); + same(); + return rc; + } +} + +namespace Constexpr { + struct Q { int a, b; constexpr Q() : a(1), b(2) {} }; + constexpr Q q; + auto &[qa, qb] = q; + static_assert(&qa == &q.a && &qb == &q.b); + static_assert(qa == 1 && qb == 2); +} + +namespace std_example { + struct S { int x1 : 2; volatile double y1; }; + S f(); + const auto [x, y] = f(); + + same same1; + same same2; +} Index: test/CodeGenOpenCL/cl20-device-side-enqueue.cl =================================================================== --- test/CodeGenOpenCL/cl20-device-side-enqueue.cl +++ test/CodeGenOpenCL/cl20-device-side-enqueue.cl @@ -21,7 +21,7 @@ // CHECK: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t*, %opencl.queue_t** %default_queue // CHECK: [[FLAGS:%[0-9]+]] = load i32, i32* %flags // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange - // CHECK: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block to void ()* + // CHECK: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(3)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block to void ()* // CHECK: [[BL_I8:%[0-9]+]] = bitcast void ()* [[BL]] to i8* // CHECK: call i32 @__enqueue_kernel_basic(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* [[BL_I8]]) enqueue_kernel(default_queue, flags, ndrange, @@ -32,7 +32,7 @@ // CHECK: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t*, %opencl.queue_t** %default_queue // CHECK: [[FLAGS:%[0-9]+]] = load i32, i32* %flags // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange - // CHECK: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block3 to void ()* + // CHECK: [[BL:%[0-9]+]] = bitcast <{ i8*, i32, i32, i8*, %struct.__block_descriptor addrspace(3)*, i32{{.*}}, i32{{.*}}, i32{{.*}} }>* %block3 to void ()* // CHECK: [[BL_I8:%[0-9]+]] = bitcast void ()* [[BL]] to i8* // CHECK: call i32 @__enqueue_kernel_basic_events(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i32 2, %opencl.clk_event_t** %event_wait_list, %opencl.clk_event_t** %clk_event, i8* [[BL_I8]]) enqueue_kernel(default_queue, flags, ndrange, 2, &event_wait_list, &clk_event, @@ -43,7 +43,7 @@ // CHECK: [[DEF_Q:%[0-9]+]] = load %opencl.queue_t*, %opencl.queue_t** %default_queue // CHECK: [[FLAGS:%[0-9]+]] = load i32, i32* %flags // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange - // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256) + // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(3)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256) enqueue_kernel(default_queue, flags, ndrange, ^(local void *p) { return; @@ -54,7 +54,7 @@ // CHECK: [[FLAGS:%[0-9]+]] = load i32, i32* %flags // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange // CHECK: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i32 - // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]]) + // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i8*, i32, ...) @__enqueue_kernel_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(3)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]]) enqueue_kernel(default_queue, flags, ndrange, ^(local void *p) { return; @@ -65,7 +65,7 @@ // CHECK: [[FLAGS:%[0-9]+]] = load i32, i32* %flags // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange // CHECK: [[AD:%arraydecay[0-9]*]] = getelementptr inbounds [1 x %opencl.clk_event_t*], [1 x %opencl.clk_event_t*]* %event_wait_list2, i32 0, i32 0 - // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t**, %opencl.clk_event_t**, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i32 2, %opencl.clk_event_t** [[AD]], %opencl.clk_event_t** %clk_event, i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256) + // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t**, %opencl.clk_event_t**, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i32 2, %opencl.clk_event_t** [[AD]], %opencl.clk_event_t** %clk_event, i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(3)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 256) enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event, ^(local void *p) { return; @@ -77,7 +77,7 @@ // CHECK: [[NDR:%[0-9]+]] = load %opencl.ndrange_t*, %opencl.ndrange_t** %ndrange // CHECK: [[AD:%arraydecay[0-9]*]] = getelementptr inbounds [1 x %opencl.clk_event_t*], [1 x %opencl.clk_event_t*]* %event_wait_list2, i32 0, i32 0 // CHECK: [[SIZE:%[0-9]+]] = zext i8 {{%[0-9]+}} to i32 - // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t**, %opencl.clk_event_t**, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i32 2, %opencl.clk_event_t** [[AD]], %opencl.clk_event_t** %clk_event, i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]]) + // CHECK: call i32 (%opencl.queue_t*, i32, %opencl.ndrange_t*, i32, %opencl.clk_event_t**, %opencl.clk_event_t**, i8*, i32, ...) @__enqueue_kernel_events_vaargs(%opencl.queue_t* [[DEF_Q]], i32 [[FLAGS]], %opencl.ndrange_t* [[NDR]], i32 2, %opencl.clk_event_t** [[AD]], %opencl.clk_event_t** %clk_event, i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor addrspace(3)* }* @__block_literal_global{{(.[0-9]+)?}} to i8*), i32 1, i32 [[SIZE]]) enqueue_kernel(default_queue, flags, ndrange, 2, event_wait_list2, &clk_event, ^(local void *p) { return; Index: test/Driver/cloudabi.c =================================================================== --- test/Driver/cloudabi.c +++ test/Driver/cloudabi.c @@ -1,8 +1,14 @@ // RUN: %clang %s -### -target x86_64-unknown-cloudabi 2>&1 | FileCheck %s -check-prefix=SAFESTACK // SAFESTACK: "-cc1" "-triple" "x86_64-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" {{.*}} "-fsanitize=safe-stack" -// SAFESTACK: "-Bstatic" "-pie" "--no-dynamic-linker" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc" "-lcompiler_rt" "crtend.o" +// SAFESTACK: "-Bstatic" "--no-dynamic-linker" "-pie" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc" "-lcompiler_rt" "crtend.o" // RUN: %clang %s -### -target x86_64-unknown-cloudabi -fno-sanitize=safe-stack 2>&1 | FileCheck %s -check-prefix=NOSAFESTACK // NOSAFESTACK: "-cc1" "-triple" "x86_64-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" // NOSAFESTACK-NOT: "-fsanitize=safe-stack" -// NOSAFESTACK: "-Bstatic" "-pie" "--no-dynamic-linker" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc" "-lcompiler_rt" "crtend.o" +// NOSAFESTACK: "-Bstatic" "--no-dynamic-linker" "-pie" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc" "-lcompiler_rt" "crtend.o" + +// PIE shouldn't be enabled on i686. Just on architectures that provide +// PC-relative addressing. +// RUN: %clang %s -### -target i686-unknown-cloudabi 2>&1 | FileCheck %s -check-prefix=NOPIE +// NOPIE: "-cc1" "-triple" "i686-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" {{.*}} "-fsanitize=safe-stack" +// NOPIE: "-Bstatic" "--no-dynamic-linker" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc" "-lcompiler_rt" "crtend.o" Index: test/Driver/cloudabi.cpp =================================================================== --- test/Driver/cloudabi.cpp +++ test/Driver/cloudabi.cpp @@ -1,8 +1,14 @@ // RUN: %clangxx %s -### -target x86_64-unknown-cloudabi 2>&1 | FileCheck %s -check-prefix=SAFESTACK // SAFESTACK: "-cc1" "-triple" "x86_64-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" {{.*}} "-fsanitize=safe-stack" -// SAFESTACK: "-Bstatic" "-pie" "--no-dynamic-linker" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc++" "-lc++abi" "-lunwind" "-lc" "-lcompiler_rt" "crtend.o" +// SAFESTACK: "-Bstatic" "--no-dynamic-linker" "-pie" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc++" "-lc++abi" "-lunwind" "-lc" "-lcompiler_rt" "crtend.o" -// RUN: %clangxx %s -### -target x86_64-unknown-cloudabi -fno-sanitize=safe-stack 2>&1 | FileCheck %s -check-prefix=NOSAFESTACk +// RUN: %clangxx %s -### -target x86_64-unknown-cloudabi -fno-sanitize=safe-stack 2>&1 | FileCheck %s -check-prefix=NOSAFESTACK // NOSAFESTACK: "-cc1" "-triple" "x86_64-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" // NOSAFESTACK-NOT: "-fsanitize=safe-stack" -// NOSAFESTACk: "-Bstatic" "-pie" "--no-dynamic-linker" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc++" "-lc++abi" "-lunwind" "-lc" "-lcompiler_rt" "crtend.o" +// NOSAFESTACK: "-Bstatic" "--no-dynamic-linker" "-pie" "-zrelro" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc++" "-lc++abi" "-lunwind" "-lc" "-lcompiler_rt" "crtend.o" + +// PIE shouldn't be enabled on i686. Just on architectures that provide +// PC-relative addressing. +// RUN: %clangxx %s -### -target i686-unknown-cloudabi 2>&1 | FileCheck %s -check-prefix=NOPIE +// NOPIE: "-cc1" "-triple" "i686-unknown-cloudabi" {{.*}} "-ffunction-sections" "-fdata-sections" {{.*}} "-fsanitize=safe-stack" +// NOPIE: "-Bstatic" "--no-dynamic-linker" "--eh-frame-hdr" "--gc-sections" "-o" "a.out" "crt0.o" "crtbegin.o" "{{.*}}" "{{.*}}" "-lc++" "-lc++abi" "-lunwind" "-lc" "-lcompiler_rt" "crtend.o" Index: test/Driver/cuda-detect.cu =================================================================== --- test/Driver/cuda-detect.cu +++ test/Driver/cuda-detect.cu @@ -74,7 +74,7 @@ // Verify that C++ include paths are passed for both host and device frontends. // RUN: %clang -### -no-canonical-prefixes -target x86_64-linux-gnu %s \ -// RUN: --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree2 2>&1 \ +// RUN: --stdlib=libstdc++ --sysroot=%S/Inputs/ubuntu_14.04_multiarch_tree2 2>&1 \ // RUN: | FileCheck %s --check-prefix CHECK-CXXINCLUDE // CHECK: Found CUDA installation: {{.*}}/Inputs/CUDA/usr/local/cuda Index: test/Driver/frame-pointer-elim.c =================================================================== --- test/Driver/frame-pointer-elim.c +++ test/Driver/frame-pointer-elim.c @@ -8,6 +8,15 @@ // RUN: FileCheck --check-prefix=LINUX %s // LINUX-NOT: "-momit-leaf-frame-pointer" +// CloudABI follows the same rules as Linux. +// RUN: %clang -### -target x86_64-unknown-cloudabi -S -O1 %s 2>&1 | \ +// RUN: FileCheck --check-prefix=CLOUDABI-OPT %s +// CLOUDABI-OPT: "-momit-leaf-frame-pointer" + +// RUN: %clang -### -target x86_64-unknown-cloudabi -S %s 2>&1 | \ +// RUN: FileCheck --check-prefix=CLOUDABI %s +// CLOUDABI-NOT: "-momit-leaf-frame-pointer" + // Darwin disables omitting the leaf frame pointer even under optimization // unless the command lines are given. // RUN: %clang -### -target i386-apple-darwin -S %s 2>&1 | \ Index: test/Modules/crash-vfs-run-reproducer.m =================================================================== --- test/Modules/crash-vfs-run-reproducer.m +++ test/Modules/crash-vfs-run-reproducer.m @@ -36,6 +36,7 @@ // CHECKYAML: 'case-sensitive': // CHECKYAML-NEXT: 'use-external-names': 'false', // CHECKYAML-NEXT: 'overlay-relative': 'true', +// CHECKYAML-NEXT: 'ignore-non-existent-contents': 'false' // CHECKYAML: 'type': 'directory' // CHECKYAML: 'name': "/[[PATH:.*]]/Inputs/crash-recovery/usr/include", // CHECKYAML-NEXT: 'contents': [ Index: test/PCH/cxx1z-decomposition.cpp =================================================================== --- /dev/null +++ test/PCH/cxx1z-decomposition.cpp @@ -0,0 +1,32 @@ +// No PCH: +// RUN: %clang_cc1 -pedantic -std=c++1z -include %s -verify %s +// +// With PCH: +// RUN: %clang_cc1 -pedantic -std=c++1z -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic -std=c++1z -include-pch %t -verify %s + +#ifndef HEADER +#define HEADER + +template auto decomp(const T &t) { + auto &[a, b] = t; + return a + b; +} + +struct Q { int a, b; }; +constexpr int foo(Q &&q) { + auto &[a, b] = q; + return a * 10 + b; +} + +#else + +int arr[2]; +int k = decomp(arr); + +static_assert(foo({1, 2}) == 12); + +// expected-error@12 {{cannot decompose non-class, non-array type 'const int'}} +int z = decomp(10); // expected-note {{instantiation of}} + +#endif Index: test/Parser/cxx1z-decomposition.cpp =================================================================== --- test/Parser/cxx1z-decomposition.cpp +++ test/Parser/cxx1z-decomposition.cpp @@ -67,7 +67,7 @@ // storage-class-specifiers static auto &[a] = n; // expected-error {{cannot be declared 'static'}} thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}} - extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} + extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}} struct S { mutable auto &[d] = n; // expected-error {{not permitted in this context}} @@ -97,7 +97,7 @@ auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -133,3 +133,16 @@ // FIXME: There's no actual rule against this... template auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}} } + +namespace Init { + void f() { + int arr[1]; + struct S { int n; }; + auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} + const auto &[bad2](S{}); // expected-error {{decomposition declaration '[bad2]' cannot have a parenthesized initializer}} + auto &[good1] = arr; + auto &&[good2] = S{}; + S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} + S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} + } +} Index: test/Sema/enable_if.c =================================================================== --- test/Sema/enable_if.c +++ test/Sema/enable_if.c @@ -149,4 +149,25 @@ regular_enable_if(1, 2); // expected-error{{too many arguments}} regular_enable_if(); // expected-error{{too few arguments}} } + +// We had a bug where we'd crash upon trying to evaluate varargs. +void variadic_enable_if(int a, ...) __attribute__((enable_if(a, ""))); // expected-note 6 {{disabled}} +void variadic_test() { + variadic_enable_if(1); + variadic_enable_if(1, 2); + variadic_enable_if(1, "c", 3); + + variadic_enable_if(0); // expected-error{{no matching}} + variadic_enable_if(0, 2); // expected-error{{no matching}} + variadic_enable_if(0, "c", 3); // expected-error{{no matching}} + + int m; + variadic_enable_if(1); + variadic_enable_if(1, m); + variadic_enable_if(1, m, "c"); + + variadic_enable_if(0); // expected-error{{no matching}} + variadic_enable_if(0, m); // expected-error{{no matching}} + variadic_enable_if(0, m, 3); // expected-error{{no matching}} +} #endif Index: test/Sema/shift.c =================================================================== --- test/Sema/shift.c +++ test/Sema/shift.c @@ -67,3 +67,14 @@ (void) (x >> 80); // no-warning (void) (x >> 80); // expected-warning {{shift count >= width of type}} } + +typedef unsigned vec16 __attribute__((vector_size(16))); +typedef unsigned vec8 __attribute__((vector_size(8))); + +void vect_shift_1(vec16 *x) { *x = *x << 4; } + +void vect_shift_2(vec16 *x, vec16 y) { *x = *x << y; } + +void vect_shift_3(vec16 *x, vec8 y) { + *x = *x << y; // expected-error {{vector operands do not have the same number of elements}} +} Index: test/SemaCXX/cxx1z-decomposition.cpp =================================================================== --- test/SemaCXX/cxx1z-decomposition.cpp +++ test/SemaCXX/cxx1z-decomposition.cpp @@ -4,8 +4,38 @@ auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}} } -// FIXME: create correct bindings -// FIXME: template instantiation -// FIXME: ast file support +// As a Clang extension, _Complex can be decomposed. +float decompose_complex(_Complex float cf) { + static _Complex float scf; + auto &[sre, sim] = scf; + // ok, this is references initialized by constant expressions all the way down + static_assert(&sre == &__real scf); + static_assert(&sim == &__imag scf); + + auto [re, im] = cf; + return re*re + im*im; +} + +// As a Clang extension, vector types can be decomposed. +typedef float vf3 __attribute__((ext_vector_type(3))); +float decompose_vector(vf3 v) { + auto [x, y, z] = v; + auto *p = &x; // expected-error {{address of vector element requested}} + return x + y + z; +} + +struct S { int a, b; }; +constexpr int f(S s) { + auto &[a, b] = s; + return a * 10 + b; +} +static_assert(f({1, 2}) == 12); + +constexpr bool g(S &&s) { + auto &[a, b] = s; + return &a == &s.a && &b == &s.b && &a != &b; +} +static_assert(g({1, 2})); + +// FIXME: by-value array copies // FIXME: code generation -// FIXME: constant expression evaluation Index: test/SemaCXX/enable_if.cpp =================================================================== --- test/SemaCXX/enable_if.cpp +++ test/SemaCXX/enable_if.cpp @@ -417,3 +417,26 @@ constexpr int B = callTemplated<0>(); // expected-error{{initialized by a constant expression}} expected-error@-2{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-9{{candidate disabled}} static_assert(callTemplated<1>() == 1, ""); } + +namespace variadic { +void foo(int a, int b = 0, ...) __attribute__((enable_if(a && b, ""))); // expected-note 6{{disabled}} + +void testFoo() { + foo(1, 1); + foo(1, 1, 2); + foo(1, 1, 2, 3); + + foo(1, 0); // expected-error{{no matching}} + foo(1, 0, 2); // expected-error{{no matching}} + foo(1, 0, 2, 3); // expected-error{{no matching}} + + int m; + foo(1, 1); + foo(1, 1, m); + foo(1, 1, m, 3); + + foo(1, 0); // expected-error{{no matching}} + foo(1, 0, m); // expected-error{{no matching}} + foo(1, 0, m, 3); // expected-error{{no matching}} +} +} Index: test/SemaCXX/warn-memset-bad-sizeof.cpp =================================================================== --- test/SemaCXX/warn-memset-bad-sizeof.cpp +++ test/SemaCXX/warn-memset-bad-sizeof.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-sizeof-array-argument %s // +extern "C" void *bzero(void *, unsigned); extern "C" void *memset(void *, int, unsigned); extern "C" void *memmove(void *s1, const void *s2, unsigned n); extern "C" void *memcpy(void *s1, const void *s2, unsigned n); @@ -47,6 +48,19 @@ memset(heap_buffer, 0, sizeof(heap_buffer)); // \ // expected-warning {{'memset' call operates on objects of type 'char' while the size is based on a different type 'char *'}} expected-note{{did you mean to provide an explicit length?}} + bzero(&s, sizeof(&s)); // \ + // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} + bzero(ps, sizeof(ps)); // \ + // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} + bzero(ps2, sizeof(ps2)); // \ + // expected-warning {{'bzero' call operates on objects of type 'S' while the size is based on a different type 'PS' (aka 'S *')}} expected-note{{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}} + bzero(ps2, sizeof(typeof(ps2))); // \ + // expected-warning {{argument to 'sizeof' in 'bzero' call is the same pointer type}} + bzero(ps2, sizeof(PS)); // \ + // expected-warning {{argument to 'sizeof' in 'bzero' call is the same pointer type}} + bzero(heap_buffer, sizeof(heap_buffer)); // \ + // expected-warning {{'bzero' call operates on objects of type 'char' while the size is based on a different type 'char *'}} expected-note{{did you mean to provide an explicit length?}} + memcpy(&s, 0, sizeof(&s)); // \ // expected-warning {{'memcpy' call operates on objects of type 'S' while the size is based on a different type 'S *'}} expected-note{{did you mean to remove the addressof in the argument to 'sizeof' (and multiply it by the number of elements)?}} memcpy(0, &s, sizeof(&s)); // \ @@ -73,6 +87,21 @@ memset(arr, 0, sizeof(arr)); memset(parr, 0, sizeof(parr)); + bzero((void*)&s, sizeof(&s)); + bzero(&s, sizeof(s)); + bzero(&s, sizeof(S)); + bzero(&s, sizeof(const S)); + bzero(&s, sizeof(volatile S)); + bzero(&s, sizeof(volatile const S)); + bzero(&foo, sizeof(CFoo)); + bzero(&foo, sizeof(VFoo)); + bzero(&foo, sizeof(CVFoo)); + bzero(ps, sizeof(*ps)); + bzero(ps2, sizeof(*ps2)); + bzero(ps2, sizeof(typeof(*ps2))); + bzero(arr, sizeof(arr)); + bzero(parr, sizeof(parr)); + memcpy(&foo, &const_foo, sizeof(Foo)); memcpy((void*)&s, 0, sizeof(&s)); memcpy(0, (void*)&s, sizeof(&s)); @@ -96,12 +125,17 @@ int iarr[14]; memset(&iarr[0], 0, sizeof iarr); memset(iarr, 0, sizeof iarr); + bzero(&iarr[0], sizeof iarr); + bzero(iarr, sizeof iarr); int* iparr[14]; memset(&iparr[0], 0, sizeof iparr); memset(iparr, 0, sizeof iparr); + bzero(&iparr[0], sizeof iparr); + bzero(iparr, sizeof iparr); memset(m, 0, sizeof(Mat)); + bzero(m, sizeof(Mat)); // Copy to raw buffer shouldn't warn either memcpy(&foo, &arr, sizeof(Foo)); @@ -114,12 +148,21 @@ for (;;) {} &s; }), 0, sizeof(s)); + + bzero(({ + if (0) {} + while (0) {} + for (;;) {} + &s; + }), sizeof(s)); } namespace ns { void memset(void* s, char c, int n); +void bzero(void* s, int n); void f(int* i) { memset(i, 0, sizeof(i)); + bzero(i, sizeof(i)); } } Index: test/SemaTemplate/cxx1z-decomposition.cpp =================================================================== --- /dev/null +++ test/SemaTemplate/cxx1z-decomposition.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +struct A { int x, y; }; +typedef int B[2]; +struct C { template int get(); }; +struct D { int x, y, z; }; +struct E { int *p, n; }; + +namespace std { + using size_t = decltype(sizeof(0)); + template struct tuple_size; + template struct tuple_element { using type = int; }; +} + +template<> struct std::tuple_size { enum { value = 2 }; }; + +template int decomp(T &t) { + auto &[a, b] = t; // expected-error {{type 'D' decomposes into 3 elements, but only 2 names were provided}} + return a + b; // expected-error {{cannot initialize return object of type 'int' with an rvalue of type 'int *'}} +} + +void test() { + A a; + B b; + C c; + D d; + E e; + decomp(a); + decomp(b); + decomp(c); + decomp(d); // expected-note {{in instantiation of}} + decomp(e); // expected-note {{in instantiation of}} +} Index: test/VFS/Inputs/vfsoverlay2.yaml =================================================================== --- test/VFS/Inputs/vfsoverlay2.yaml +++ test/VFS/Inputs/vfsoverlay2.yaml @@ -1,5 +1,6 @@ { 'version': 0, + 'ignore-non-existent-contents': false, 'roots': [ { 'name': 'OUT_DIR', 'type': 'directory', 'contents': [ Index: tools/driver/CMakeLists.txt =================================================================== --- tools/driver/CMakeLists.txt +++ tools/driver/CMakeLists.txt @@ -101,8 +101,15 @@ # This is a test to ensure the actual order file works with the linker. check_linker_flag("-Wl,-order_file,${CLANG_ORDER_FILE}" LINKER_ORDER_FILE_WORKS) - - if(LINKER_ORDER_FILE_WORKS) + + # Passing an empty order file disables some linker layout optimizations. + # To work around this and enable workflows for re-linking when the order file + # changes we check during configuration if the file is empty, and make it a + # configuration dependency. + file(READ ${CLANG_ORDER_FILE} ORDER_FILE LIMIT 20) + if("${ORDER_FILE}" STREQUAL "\n") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CLANG_ORDER_FILE}) + elseif(LINKER_ORDER_FILE_WORKS) target_link_libraries(clang "-Wl,-order_file,${CLANG_ORDER_FILE}") set_target_properties(clang PROPERTIES LINK_DEPENDS ${CLANG_ORDER_FILE}) endif() Index: unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp =================================================================== --- unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp +++ unittests/Tooling/RecursiveASTVisitorTestExprVisitor.cpp @@ -161,10 +161,21 @@ class DeclRefExprVisitor : public ExpectedLocationVisitor { public: + DeclRefExprVisitor() : ShouldVisitImplicitCode(false) {} + + bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; } + + void setShouldVisitImplicitCode(bool NewValue) { + ShouldVisitImplicitCode = NewValue; + } + bool VisitDeclRefExpr(DeclRefExpr *Reference) { Match(Reference->getNameInfo().getAsString(), Reference->getLocation()); return true; } + +private: + bool ShouldVisitImplicitCode; }; TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) { @@ -191,14 +202,44 @@ "void x(); void y() { x(); }")); } -TEST(RecursiveASTVisitor, VisitsLambdaCaptureInit) { +TEST(RecursiveASTVisitor, VisitsExplicitLambdaCaptureInit) { DeclRefExprVisitor Visitor; Visitor.ExpectMatch("i", 1, 20); EXPECT_TRUE(Visitor.runOver( - "void f() { int i; [i]{}; };", + "void f() { int i; [i]{}; }", DeclRefExprVisitor::Lang_CXX11)); } +TEST(RecursiveASTVisitor, VisitsImplicitLambdaCaptureInit) { + { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("i", 1, 24); + EXPECT_TRUE(Visitor.runOver( + "void f() { int i; [=]{ i; }; }", + DeclRefExprVisitor::Lang_CXX11)); + } + { + DeclRefExprVisitor Visitor; + Visitor.setShouldVisitImplicitCode(true); + // We're expecting the "i" in the lambda to be visited twice: + // - Once for the DeclRefExpr in the lambda capture initialization (whose + // source code location is set to the first use of the variable). + // - Once for the DeclRefExpr for the use of "i" inside the lambda. + Visitor.ExpectMatch("i", 1, 24, /* Times = */ 2); + EXPECT_TRUE(Visitor.runOver( + "void f() { int i; [=]{ i; }; }", + DeclRefExprVisitor::Lang_CXX11)); + } +} + +TEST(RecursiveASTVisitor, VisitsLambdaInitCaptureInit) { + DeclRefExprVisitor Visitor; + Visitor.ExpectMatch("i", 1, 24); + EXPECT_TRUE(Visitor.runOver( + "void f() { int i; [a = i + 1]{}; }", + DeclRefExprVisitor::Lang_CXX14)); +} + /* FIXME: According to Richard Smith this is a bug in the AST. TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) { DeclRefExprVisitor Visitor; Index: unittests/Tooling/TestVisitor.h =================================================================== --- unittests/Tooling/TestVisitor.h +++ unittests/Tooling/TestVisitor.h @@ -43,6 +43,7 @@ Lang_C, Lang_CXX98, Lang_CXX11, + Lang_CXX14, Lang_OBJC, Lang_OBJCXX11, Lang_CXX = Lang_CXX98 @@ -55,6 +56,7 @@ case Lang_C: Args.push_back("-std=c99"); break; case Lang_CXX98: Args.push_back("-std=c++98"); break; case Lang_CXX11: Args.push_back("-std=c++11"); break; + case Lang_CXX14: Args.push_back("-std=c++14"); break; case Lang_OBJC: Args.push_back("-ObjC"); break; case Lang_OBJCXX11: Args.push_back("-ObjC++"); @@ -127,9 +129,12 @@ /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'. /// /// Any number of expected matches can be set by calling this repeatedly. - /// Each is expected to be matched exactly once. - void ExpectMatch(Twine Match, unsigned Line, unsigned Column) { - ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column)); + /// Each is expected to be matched 'Times' number of times. (This is useful in + /// cases in which different AST nodes can match at the same source code + /// location.) + void ExpectMatch(Twine Match, unsigned Line, unsigned Column, + unsigned Times = 1) { + ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times)); } /// \brief Checks that all expected matches have been found. @@ -200,14 +205,17 @@ }; struct ExpectedMatch { - ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber) - : Candidate(Name, LineNumber, ColumnNumber), Found(false) {} + ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber, + unsigned Times) + : Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times), + TimesSeen(0) {} void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) { if (Candidate.Matches(Name, Location)) { - EXPECT_TRUE(!Found); - Found = true; - } else if (!Found && Candidate.PartiallyMatches(Name, Location)) { + EXPECT_LT(TimesSeen, TimesExpected); + ++TimesSeen; + } else if (TimesSeen < TimesExpected && + Candidate.PartiallyMatches(Name, Location)) { llvm::raw_string_ostream Stream(PartialMatches); Stream << ", partial match: \"" << Name << "\" at "; Location.print(Stream, SM); @@ -215,7 +223,7 @@ } void ExpectFound() const { - EXPECT_TRUE(Found) + EXPECT_EQ(TimesExpected, TimesSeen) << "Expected \"" << Candidate.ExpectedName << "\" at " << Candidate.LineNumber << ":" << Candidate.ColumnNumber << PartialMatches; @@ -223,7 +231,8 @@ MatchCandidate Candidate; std::string PartialMatches; - bool Found; + unsigned TimesExpected; + unsigned TimesSeen; }; std::vector DisallowedMatches;