Index: vendor/clang/dist/docs/ReleaseNotes.rst =================================================================== --- vendor/clang/dist/docs/ReleaseNotes.rst (revision 278753) +++ vendor/clang/dist/docs/ReleaseNotes.rst (revision 278754) @@ -1,187 +1,227 @@ ===================================== Clang 3.6 (In-Progress) Release Notes ===================================== .. contents:: :local: :depth: 2 Written by the `LLVM Team `_ .. warning:: These are in-progress notes for the upcoming Clang 3.6 release. You may prefer the `Clang 3.5 Release Notes `_. Introduction ============ This document contains the release notes for the Clang C/C++/Objective-C frontend, part of the LLVM Compiler Infrastructure, release 3.6. Here we describe the status of Clang in some detail, including major improvements from the previous release and new feature work. For the general LLVM release notes, see `the LLVM documentation `_. All LLVM releases may be downloaded from the `LLVM releases web site `_. For more information about Clang or LLVM, including information about the latest release, please check out the main please see the `Clang Web Site `_ or the `LLVM Web Site `_. Note that if you are reading this file from a Subversion checkout or the main Clang web page, this document applies to the *next* release, not the current one. To see the release notes for a specific release, please see the `releases page `_. What's New in Clang 3.6? ======================== Some of the major new features and improvements to Clang are listed here. Generic improvements to Clang as a whole or to its underlying infrastructure are described first, followed by language-specific sections with improvements to Clang's support for those languages. Major New Features ------------------ - The __has_attribute built-in macro no longer queries for attributes across multiple attribute syntaxes (GNU, C++11, __declspec, etc). Instead, it only queries GNU-style attributes. With the addition of __has_cpp_attribute and __has_declspec_attribute, this allows for more precise coverage of attribute syntax querying. - clang-format now supports formatting Java code. Improvements to Clang's diagnostics ----------------------------------- Clang's diagnostics are constantly being improved to catch more issues, explain them more clearly, and provide more accurate source information about them. The improvements since the 3.5 release include: - ... New Compiler Flags ------------------ The option .... The __EXCEPTIONS macro ---------------------- ``__EXCEPTIONS`` is now defined when landing pads are emitted, not when c++ exceptions are enabled. The two can be different in Objective-C files: If C++ exceptions are disabled but Objective-C exceptions are enabled, landing pads will be emitted. Clang 3.6 is switching the behavior of ``__EXCEPTIONS``. Clang 3.5 confusingly changed the behavior of ``has_feature(cxx_exceptions)``, which used to be set if landing pads were emitted, but is now set if C++ exceptions are enabled. So there are 3 cases: Clang before 3.5: ``__EXCEPTIONS`` is set if C++ exceptions are enabled, ``cxx_exceptions`` enabled if C++ or ObjC exceptions are enabled Clang 3.5: ``__EXCEPTIONS`` is set if C++ exceptions are enabled, ``cxx_exceptions`` enabled if C++ exceptions are enabled Clang 3.6: ``__EXCEPTIONS`` is set if C++ or ObjC exceptions are enabled, ``cxx_exceptions`` enabled if C++ exceptions are enabled To reliably test if C++ exceptions are enabled, use ``__EXCEPTIONS && __has_feature(cxx_exceptions)``, else things won't work in all versions of clang in Objective-C++ files. New Pragmas in Clang ----------------------- Clang now supports the ... Windows Support --------------- - Many, many bug fixes - Basic support for DWARF debug information in COFF files +- Support for Visual C++ '__super' keyword + C Language Changes in Clang --------------------------- ... C11 Feature Support ^^^^^^^^^^^^^^^^^^^ ... C++ Language Changes in Clang ----------------------------- - Clang now supports putting identical constructors and destructors in the C5/D5 comdat, reducing code duplication. - Clang will put individual ``.init_array/.ctors`` sections in comdats, reducing code duplication and speeding up startup. -C++11 Feature Support +C++17 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -... +Clang has experimental support for some proposed C++1z (tentatively, C++17) +features. This support can be enabled using the `-std=c++1z` flag. +New in Clang 3.6 is support for: + +- Fold expressions + +- `u8` character literals + +- Nested namespace definitions: `namespace A::B { ... }` as a shorthand for + `namespace A { namespace B { ... } }` + +- Attributes for namespaces and enumerators + +- Constant evaluation for all non-type template arguments + +Note that these features may be changed or removed in future Clang releases +without notice. + +Support for `for (identifier : range)` as a synonym for +`for (auto &&identifier : range)` has been removed as it is no longer currently +considered for C++17. + +For more details on C++ feature support, see +`the C++ status page `_. + + Objective-C Language Changes in Clang ------------------------------------- ... OpenCL C Language Changes in Clang ---------------------------------- ... + +OpenMP Language Changes in Clang +-------------------------------- + +Clang 3.6 contains codegen for many individual pragmas for OpenMP but combinations are not completed as yet. +We plan to continue codegen code drop aiming for completion for 3.7. Please see this link for up-to-date +`status _` +LLVM’s OpenMP runtime library, originally developed by Intel, has been modified to work on ARM, PowerPC, +as well as X86. The Runtime Library's compatibility with GCC 4.9 is improved +- missed entry points added, Barrier and fork/join code improved, one more type of barrier enabled. +Support for ppc64le architecture is now available and automatically detected when using cmake system. +Using makefile the new "ppc64le" arch type is available. +Contributors to this work include AMD, Argonne National Lab., IBM, Intel, Texas Instruments, University of Houston and many others. Internal API Changes -------------------- These are major API changes that have happened since the 3.5 release of Clang. If upgrading an external codebase that uses Clang as a library, this section should help get you past the largest hurdles of upgrading. ... libclang -------- ... Static Analyzer --------------- ... Core Analysis Improvements ========================== - ... New Issues Found ================ - ... Python Binding Changes ---------------------- The following methods have been added: - ... Significant Known Problems ========================== Additional Information ====================== A wide variety of additional information is available on the `Clang web page `_. The web page contains versions of the API documentation which are up-to-date with the Subversion version of the source code. You can access versions of these documents specific to this release by going into the "``clang/docs/``" directory in the Clang tree. If you have any questions or comments about Clang, please feel free to contact us via the `mailing list `_. Index: vendor/clang/dist/include/clang/Basic/DiagnosticGroups.td =================================================================== --- vendor/clang/dist/include/clang/Basic/DiagnosticGroups.td (revision 278753) +++ vendor/clang/dist/include/clang/Basic/DiagnosticGroups.td (revision 278754) @@ -1,751 +1,754 @@ //==--- DiagnosticGroups.td - Diagnostic Group Definitions ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// def ImplicitFunctionDeclare : DiagGroup<"implicit-function-declaration">; def ImplicitInt : DiagGroup<"implicit-int">; // Aggregation warning settings. def Implicit : DiagGroup<"implicit", [ ImplicitFunctionDeclare, ImplicitInt ]>; // Empty DiagGroups are recognized by clang but ignored. def : DiagGroup<"abi">; def AbsoluteValue : DiagGroup<"absolute-value">; def AddressOfTemporary : DiagGroup<"address-of-temporary">; def : DiagGroup<"aggregate-return">; def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">; def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; def Availability : DiagGroup<"availability">; def Section : DiagGroup<"section">; def AutoImport : DiagGroup<"auto-import">; def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">; def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">; def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; def LiteralConversion : DiagGroup<"literal-conversion">; def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion, UndefinedBoolConversion]>; def IntConversion : DiagGroup<"int-conversion">; def EnumConversion : DiagGroup<"enum-conversion">; def FloatConversion : DiagGroup<"float-conversion">; def EnumTooLarge : DiagGroup<"enum-too-large">; def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">; def NullConversion : DiagGroup<"null-conversion">; def ImplicitConversionFloatingPointToBool : DiagGroup<"implicit-conversion-floating-point-to-bool">; def ObjCLiteralConversion : DiagGroup<"objc-literal-conversion">; def BadArrayNewLength : DiagGroup<"bad-array-new-length">; def MacroRedefined : DiagGroup<"macro-redefined">; def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">; def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">; def C99Compat : DiagGroup<"c99-compat">; def CXXCompat: DiagGroup<"c++-compat">; def ExternCCompat : DiagGroup<"extern-c-compat">; def KeywordCompat : DiagGroup<"keyword-compat">; def GNUCaseRange : DiagGroup<"gnu-case-range">; def CastAlign : DiagGroup<"cast-align">; def CastQual : DiagGroup<"cast-qual">; def : DiagGroup<"char-align">; def Comment : DiagGroup<"comment">; def GNUComplexInteger : DiagGroup<"gnu-complex-integer">; def GNUConditionalOmittedOperand : DiagGroup<"gnu-conditional-omitted-operand">; def ConfigMacros : DiagGroup<"config-macros">; def : DiagGroup<"ctor-dtor-privacy">; def GNUDesignator : DiagGroup<"gnu-designator">; def GNUStringLiteralOperatorTemplate : DiagGroup<"gnu-string-literal-operator-template">; def DeleteIncomplete : DiagGroup<"delete-incomplete">; def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; def AbstractFinalClass : DiagGroup<"abstract-final-class">; def CXX11CompatDeprecatedWritableStr : DiagGroup<"c++11-compat-deprecated-writable-strings">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">; def DeprecatedRegister : DiagGroup<"deprecated-register">; def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings", [CXX11CompatDeprecatedWritableStr]>; // FIXME: Why is DeprecatedImplementations not in this group? def Deprecated : DiagGroup<"deprecated", [DeprecatedDeclarations, DeprecatedIncrementBool, DeprecatedRegister, DeprecatedWritableStr]>, DiagCategory<"Deprecations">; def : DiagGroup<"disabled-optimization">; def : DiagGroup<"discard-qual">; def : DiagGroup<"div-by-zero">; def DocumentationHTML : DiagGroup<"documentation-html">; def DocumentationUnknownCommand : DiagGroup<"documentation-unknown-command">; def DocumentationPedantic : DiagGroup<"documentation-pedantic", [DocumentationUnknownCommand]>; def DocumentationDeprecatedSync : DiagGroup<"documentation-deprecated-sync">; def Documentation : DiagGroup<"documentation", [DocumentationHTML, DocumentationDeprecatedSync]>; def EmptyBody : DiagGroup<"empty-body">; def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">; def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">; def ExtraTokens : DiagGroup<"extra-tokens">; def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">; def ExtraSemi : DiagGroup<"extra-semi", [CXX11ExtraSemi]>; def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">; def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; // Warnings for C++1y code which is not compatible with prior C++ standards. def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; def CXXPre14CompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", [CXXPre14Compat]>; def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", [CXXPre1zCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; def CXX98CompatLocalTypeTemplateArgs : DiagGroup<"c++98-compat-local-type-template-args">; def CXX98CompatUnnamedTypeTemplateArgs : DiagGroup<"c++98-compat-unnamed-type-template-args">; def CXX98Compat : DiagGroup<"c++98-compat", [CXX98CompatLocalTypeTemplateArgs, CXX98CompatUnnamedTypeTemplateArgs, CXXPre14Compat, CXXPre1zCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, CXX98CompatBindToTemporaryCopy, CXXPre14CompatPedantic, CXXPre1zCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">; // Original name of this warning in Clang def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>; // Name of this warning in GCC def : DiagGroup<"narrowing", [CXX11Narrowing]>; def CXX11CompatReservedUserDefinedLiteral : DiagGroup<"c++11-compat-reserved-user-defined-literal">; def ReservedUserDefinedLiteral : DiagGroup<"reserved-user-defined-literal", [CXX11CompatReservedUserDefinedLiteral]>; def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing, CXX11CompatReservedUserDefinedLiteral, CXX11CompatDeprecatedWritableStr, CXXPre14Compat, CXXPre1zCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", [CXXPre14CompatPedantic, CXXPre1zCompatPedantic]>; def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", [CXXPre1zCompatPedantic]>; def : DiagGroup<"effc++">; def DivZero : DiagGroup<"division-by-zero">; def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; def FourByteMultiChar : DiagGroup<"four-char-constants">; def GlobalConstructors : DiagGroup<"global-constructors">; def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; def LogicalNotParentheses: DiagGroup<"logical-not-parentheses">; def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">; def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">; def DanglingElse: DiagGroup<"dangling-else">; def DanglingField : DiagGroup<"dangling-field">; def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; def InfiniteRecursion : DiagGroup<"infinite-recursion">; def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">; def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; def : DiagGroup<"import">; def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">; def IncompatiblePointerTypesDiscardsQualifiers : DiagGroup<"incompatible-pointer-types-discards-qualifiers">; def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types", [IncompatiblePointerTypesDiscardsQualifiers]>; def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; def NonModularIncludeInFrameworkModule : DiagGroup<"non-modular-include-in-framework-module">; def NonModularIncludeInModule : DiagGroup<"non-modular-include-in-module", [NonModularIncludeInFrameworkModule]>; def IncompleteModule : DiagGroup<"incomplete-module", [IncompleteUmbrella, NonModularIncludeInModule]>; def InvalidNoreturn : DiagGroup<"invalid-noreturn">; def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">; def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">; def : DiagGroup<"init-self">; def : DiagGroup<"inline">; def : DiagGroup<"invalid-pch">; def GNULabelsAsValue : DiagGroup<"gnu-label-as-value">; def LiteralRange : DiagGroup<"literal-range">; def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args", [CXX98CompatLocalTypeTemplateArgs]>; def LoopAnalysis : DiagGroup<"loop-analysis">; def MalformedWarningCheck : DiagGroup<"malformed-warning-check">; def Main : DiagGroup<"main">; def MainReturnType : DiagGroup<"main-return-type">; def MissingBraces : DiagGroup<"missing-braces">; def MissingDeclarations: DiagGroup<"missing-declarations">; def : DiagGroup<"missing-format-attribute">; def : DiagGroup<"missing-include-dirs">; def MissingNoreturn : DiagGroup<"missing-noreturn">; def MultiChar : DiagGroup<"multichar">; def : DiagGroup<"nested-externs">; def CXX11LongLong : DiagGroup<"c++11-long-long">; def LongLong : DiagGroup<"long-long", [CXX11LongLong]>; def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; def ModuleBuild : DiagGroup<"module-build">; def ModuleConflict : DiagGroup<"module-conflict">; def NewlineEOF : DiagGroup<"newline-eof">; def NullArithmetic : DiagGroup<"null-arithmetic">; def NullCharacter : DiagGroup<"null-character">; def NullDereference : DiagGroup<"null-dereference">; def InitializerOverrides : DiagGroup<"initializer-overrides">; def NonNull : DiagGroup<"nonnull">; def NonPODVarargs : DiagGroup<"non-pod-varargs">; def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>; def : DiagGroup<"nonportable-cfstrings">; def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def OveralignedType : DiagGroup<"over-aligned">; def OldStyleCast : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; def : DiagGroup<"overflow">; def ForwardClassReceiver : DiagGroup<"receiver-forward-class">; def MethodAccess : DiagGroup<"objc-method-access">; def ObjCReceiver : DiagGroup<"receiver-expr">; def OperatorNewReturnsNull : DiagGroup<"new-returns-null">; def OverlengthStrings : DiagGroup<"overlength-strings">; def OverloadedVirtual : DiagGroup<"overloaded-virtual">; def PrivateExtern : DiagGroup<"private-extern">; def SelTypeCast : DiagGroup<"cast-of-sel-type">; def FunctionDefInObjCContainer : DiagGroup<"function-def-in-objc-container">; def BadFunctionCast : DiagGroup<"bad-function-cast">; def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">; def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">; def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">; def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">; def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">; def ObjCRootClass : DiagGroup<"objc-root-class">; def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">; def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; def Packed : DiagGroup<"packed">; def Padded : DiagGroup<"padded">; def PointerArith : DiagGroup<"pointer-arith">; def PoundWarning : DiagGroup<"#warnings">; def PoundPragmaMessage : DiagGroup<"#pragma-messages">, DiagCategory<"#pragma message Directive">; def : DiagGroup<"pointer-to-int-cast">; def : DiagGroup<"redundant-decls">; def RedeclaredClassMember : DiagGroup<"redeclared-class-member">; def GNURedeclaredEnum : DiagGroup<"gnu-redeclared-enum">; def ReturnStackAddress : DiagGroup<"return-stack-address">; def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">; def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>; def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy", [CXX98CompatBindToTemporaryCopy]>; def SelfAssignmentField : DiagGroup<"self-assign-field">; def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>; def SelfMove : DiagGroup<"self-move">; def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; def Sentinel : DiagGroup<"sentinel">; def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; def Shadow : DiagGroup<"shadow">; def Shorten64To32 : DiagGroup<"shorten-64-to-32">; def : DiagGroup<"sign-promo">; def SignCompare : DiagGroup<"sign-compare">; def : DiagGroup<"stack-protector">; def : DiagGroup<"switch-default">; def : DiagGroup<"synth">; def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">; def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">; def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">; def StaticInInline : DiagGroup<"static-in-inline">; def StaticLocalInInline : DiagGroup<"static-local-in-inline">; def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">; def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatInit]>; def GNUStatementExpression : DiagGroup<"gnu-statement-expression">; def StringCompare : DiagGroup<"string-compare">; def StringPlusInt : DiagGroup<"string-plus-int">; def StringPlusChar : DiagGroup<"string-plus-char">; def StrncatSize : DiagGroup<"strncat-size">; def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">; def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">; def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">; def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">; def TautologicalCompare : DiagGroup<"tautological-compare", [TautologicalOutOfRangeCompare, TautologicalPointerCompare, TautologicalOverlapCompare, TautologicalUndefinedCompare]>; def HeaderHygiene : DiagGroup<"header-hygiene">; def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">; def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">; def GNUUnionCast : DiagGroup<"gnu-union-cast">; def GNUVariableSizedTypeNotAtEnd : DiagGroup<"gnu-variable-sized-type-not-at-end">; def Varargs : DiagGroup<"varargs">; def Unsequenced : DiagGroup<"unsequenced">; // GCC name for -Wunsequenced def : DiagGroup<"sequence-point", [Unsequenced]>; // Preprocessor warnings. def AmbiguousMacro : DiagGroup<"ambiguous-macro">; def KeywordAsMacro : DiagGroup<"keyword-macro">; def ReservedIdAsMacro : DiagGroup<"reserved-id-macro">; // Just silence warnings about -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; def : DiagGroup<"strict-aliasing=1">; def : DiagGroup<"strict-aliasing=2">; def : DiagGroup<"strict-aliasing">; // Just silence warnings about -Wstrict-overflow for now. def : DiagGroup<"strict-overflow=0">; def : DiagGroup<"strict-overflow=1">; def : DiagGroup<"strict-overflow=2">; def : DiagGroup<"strict-overflow=3">; def : DiagGroup<"strict-overflow=4">; def : DiagGroup<"strict-overflow=5">; def : DiagGroup<"strict-overflow">; def InvalidOffsetof : DiagGroup<"invalid-offsetof">; def : DiagGroup<"strict-prototypes">; def StrictSelector : DiagGroup<"strict-selector-match">; def MethodDuplicate : DiagGroup<"duplicate-method-match">; def ObjCCStringFormat : DiagGroup<"cstring-format-directive">; def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; def SwitchBool : DiagGroup<"switch-bool">; def SwitchEnum : DiagGroup<"switch-enum">; def Switch : DiagGroup<"switch">; def ImplicitFallthroughPerFunction : DiagGroup<"implicit-fallthrough-per-function">; def ImplicitFallthrough : DiagGroup<"implicit-fallthrough", [ImplicitFallthroughPerFunction]>; def InvalidPPToken : DiagGroup<"invalid-pp-token">; def Trigraphs : DiagGroup<"trigraphs">; def : DiagGroup<"type-limits">; def UndefinedReinterpretCast : DiagGroup<"undefined-reinterpret-cast">; def ReinterpretBaseClass : DiagGroup<"reinterpret-base-class">; def Unicode : DiagGroup<"unicode">; def UninitializedMaybe : DiagGroup<"conditional-uninitialized">; def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">; def UninitializedStaticSelfInit : DiagGroup<"static-self-init">; def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes, UninitializedStaticSelfInit]>; def UnknownPragmas : DiagGroup<"unknown-pragmas">; def IgnoredPragmas : DiagGroup<"ignored-pragmas">; def Pragmas : DiagGroup<"pragmas", [UnknownPragmas, IgnoredPragmas]>; def UnknownWarningOption : DiagGroup<"unknown-warning-option">; def NSobjectAttribute : DiagGroup<"NSObject-attribute">; def UnknownAttributes : DiagGroup<"unknown-attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; def Attributes : DiagGroup<"attributes", [UnknownAttributes, IgnoredAttributes]>; def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", [CXX98CompatUnnamedTypeTemplateArgs]>; def UnsupportedFriend : DiagGroup<"unsupported-friend">; def UnusedArgument : DiagGroup<"unused-argument">; def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument">; def IgnoredOptimizationArgument : DiagGroup<"ignored-optimization-argument">; def InvalidCommandLineArgument : DiagGroup<"invalid-command-line-argument", [IgnoredOptimizationArgument]>; def UnusedComparison : DiagGroup<"unused-comparison">; def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">; def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">; def UnneededMemberFunction : DiagGroup<"unneeded-member-function">; def UnusedPrivateField : DiagGroup<"unused-private-field">; def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>; def UnusedMemberFunction : DiagGroup<"unused-member-function", [UnneededMemberFunction]>; def UnusedLabel : DiagGroup<"unused-label">; def UnusedParameter : DiagGroup<"unused-parameter">; def UnusedResult : DiagGroup<"unused-result">; def PotentiallyEvaluatedExpression : DiagGroup<"potentially-evaluated-expression">; def UnevaluatedExpression : DiagGroup<"unevaluated-expression", [PotentiallyEvaluatedExpression]>; def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult, UnevaluatedExpression]>; def UnusedConstVariable : DiagGroup<"unused-const-variable">; def UnusedVariable : DiagGroup<"unused-variable", [UnusedConstVariable]>; def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">; def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">; def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">; def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; def UserDefinedLiterals : DiagGroup<"user-defined-literals">; def Reorder : DiagGroup<"reorder">; def UndeclaredSelector : DiagGroup<"undeclared-selector">; def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; def CustomAtomic : DiagGroup<"custom-atomic-properties">; def AtomicProperties : DiagGroup<"atomic-properties", [ImplicitAtomic, CustomAtomic]>; def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">; def ARCRetainCycles : DiagGroup<"arc-retain-cycles">; def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">; def AutomaticReferenceCounting : DiagGroup<"arc", [ARCUnsafeRetainedAssign, ARCRetainCycles, ARCNonPodMemAccess]>; def ARCRepeatedUseOfWeakMaybe : DiagGroup<"arc-maybe-repeated-use-of-weak">; def ARCRepeatedUseOfWeak : DiagGroup<"arc-repeated-use-of-weak", [ARCRepeatedUseOfWeakMaybe]>; def ObjCBridge : DiagGroup<"bridge-cast">; def DeallocInCategory:DiagGroup<"dealloc-in-category">; def SelectorTypeMismatch : DiagGroup<"selector-type-mismatch">; def Selector : DiagGroup<"selector", [SelectorTypeMismatch]>; def Protocol : DiagGroup<"protocol">; def AtProtocol : DiagGroup<"at-protocol">; def PropertyAccessDotSyntax: DiagGroup<"property-access-dot-syntax">; def PropertyAttr : DiagGroup<"property-attribute-mismatch">; def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; def VariadicMacros : DiagGroup<"variadic-macros">; def VectorConversion : DiagGroup<"vector-conversion">; // clang specific def VexingParse : DiagGroup<"vexing-parse">; def VLA : DiagGroup<"vla">; def VLAExtension : DiagGroup<"vla-extension">; def VolatileRegisterVar : DiagGroup<"volatile-register-var">; def Visibility : DiagGroup<"visibility">; def ZeroLengthArray : DiagGroup<"zero-length-array">; def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">; def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">; def Fallback : DiagGroup<"fallback">; // This covers both the deprecated case (in C++98) // and the extension case (in C++11 onwards). def WritableStrings : DiagGroup<"writable-strings", [DeprecatedWritableStr]>; // GCC calls -Wdeprecated-writable-strings -Wwrite-strings. // // Bizarrely, this warning flag enables -fconst-strings in C. This is // GCC-compatible, but really weird. // // FIXME: Should this affect C++11 (where this is an error, // not just deprecated) or not? def GCCWriteStrings : DiagGroup<"write-strings" , [WritableStrings]>; def CharSubscript : DiagGroup<"char-subscripts">; def LargeByValueCopy : DiagGroup<"large-by-value-copy">; def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; // Unreachable code warning groups. // // The goal is make -Wunreachable-code on by default, in -Wall, or at // least actively used, with more noisy versions of the warning covered // under separate flags. // def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">; def UnreachableCode : DiagGroup<"unreachable-code", [UnreachableCodeLoopIncrement]>; def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">; def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">; def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive", [UnreachableCode, UnreachableCodeBreak, UnreachableCodeReturn]>; // Aggregation warning settings. // Populate -Waddress with warnings from other groups. def : DiagGroup<"address", [PointerBoolConversion, StringCompare, TautologicalPointerCompare]>; // -Widiomatic-parentheses contains warnings about 'idiomatic' // missing parentheses; it is off by default. We do not include it // in -Wparentheses because most users who use -Wparentheses explicitly // do not want these warnings. def ParenthesesOnEquality : DiagGroup<"parentheses-equality">; def Parentheses : DiagGroup<"parentheses", [LogicalOpParentheses, LogicalNotParentheses, BitwiseOpParentheses, ShiftOpParentheses, OverloadedShiftOpParentheses, ParenthesesOnEquality, DanglingElse]>; // -Wconversion has its own warnings, but we split a few out for // legacy reasons: // - some people want just 64-to-32 warnings // - conversion warnings with constant sources are on by default // - conversion warnings for literals are on by default // - bool-to-pointer conversion warnings are on by default // - __null-to-integer conversion warnings are on by default def Conversion : DiagGroup<"conversion", [BoolConversion, ConstantConversion, EnumConversion, FloatConversion, Shorten64To32, IntConversion, LiteralConversion, NonLiteralNullConversion, // (1-1)->pointer (etc) NullConversion, // NULL->non-pointer ObjCLiteralConversion, SignConversion, StringConversion]>, DiagCategory<"Value Conversion Issue">; def Unused : DiagGroup<"unused", [UnusedArgument, UnusedFunction, UnusedLabel, // UnusedParameter, (matches GCC's behavior) // UnusedMemberFunction, (clean-up llvm before enabling) UnusedPrivateField, UnusedLocalTypedef, UnusedValue, UnusedVariable, UnusedPropertyIvar]>, DiagCategory<"Unused Entity Issue">; // Format settings. def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">; def FormatSecurity : DiagGroup<"format-security">; def FormatNonStandard : DiagGroup<"format-non-iso">; def FormatY2K : DiagGroup<"format-y2k">; def Format : DiagGroup<"format", [FormatExtraArgs, FormatZeroLength, NonNull, FormatSecurity, FormatY2K, FormatInvalidSpecifier]>, DiagCategory<"Format String Issue">; def FormatNonLiteral : DiagGroup<"format-nonliteral">; def Format2 : DiagGroup<"format=2", [FormatNonLiteral, FormatSecurity, FormatY2K]>; def TypeSafety : DiagGroup<"type-safety">; def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; def IntToPointerCast : DiagGroup<"int-to-pointer-cast", [IntToVoidPointerCast]>; def Extra : DiagGroup<"extra", [ MissingFieldInitializers, IgnoredQualifiers, InitializerOverrides, SemiBeforeMethodBody, MissingMethodReturnType, SignCompare, UnusedParameter ]>; def Most : DiagGroup<"most", [ CharSubscript, Comment, DeleteNonVirtualDtor, Format, Implicit, MismatchedTags, MissingBraces, MultiChar, Reorder, ReturnType, SelfAssignment, SelfMove, SizeofArrayArgument, SizeofArrayDecay, StringPlusInt, Trigraphs, Uninitialized, UnknownPragmas, Unused, VolatileRegisterVar, ObjCMissingSuperCalls, ObjCDesignatedInit, OverloadedVirtual, PrivateExtern, SelTypeCast, ExternCCompat ]>; // Thread Safety warnings def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">; def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">; def ThreadSafetyPrecise : DiagGroup<"thread-safety-precise">; def ThreadSafetyReference : DiagGroup<"thread-safety-reference">; def ThreadSafetyNegative : DiagGroup<"thread-safety-negative">; def ThreadSafety : DiagGroup<"thread-safety", [ThreadSafetyAttributes, ThreadSafetyAnalysis, ThreadSafetyPrecise, ThreadSafetyReference]>; def ThreadSafetyVerbose : DiagGroup<"thread-safety-verbose">; def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">; // Uniqueness Analysis warnings def Consumed : DiagGroup<"consumed">; // Note that putting warnings in -Wall will not disable them by default. If a // warning should be active _only_ when -Wall is passed in, mark it as // DefaultIgnore in addition to putting it here. def : DiagGroup<"all", [Most, Parentheses, Switch, SwitchBool]>; // Warnings enabled by -pedantic. This is magically filled in by TableGen. def Pedantic : DiagGroup<"pedantic">; // Aliases. def : DiagGroup<"", [Extra]>; // -W = -Wextra def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wextra-tokens def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment def : DiagGroup<"conversion-null", [NullConversion]>; // -Wconversion-null = -Wnull-conversion def : DiagGroup<"bool-conversions", [BoolConversion]>; // -Wbool-conversions = -Wbool-conversion def : DiagGroup<"int-conversions", [IntConversion]>; // -Wint-conversions = -Wint-conversion def : DiagGroup<"vector-conversions", [VectorConversion]>; // -Wvector-conversions = -Wvector-conversion def : DiagGroup<"unused-local-typedefs", [UnusedLocalTypedef]>; // -Wunused-local-typedefs = -Wunused-local-typedef // A warning group for warnings that we want to have on by default in clang, // but which aren't on by default in GCC. def NonGCC : DiagGroup<"non-gcc", [SignCompare, Conversion, LiteralRange]>; // A warning group for warnings about using C++11 features as extensions in // earlier C++ versions. def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>; // A warning group for warnings about using C++14 features as extensions in // earlier C++ versions. def CXX14 : DiagGroup<"c++14-extensions">; // A warning group for warnings about using C++1z features as extensions in // earlier C++ versions. def CXX1z : DiagGroup<"c++1z-extensions">; def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; // A warning group for warnings about using C11 features as extensions. def C11 : DiagGroup<"c11-extensions">; // A warning group for warnings about using C99 features as extensions. def C99 : DiagGroup<"c99-extensions">; // A warning group for warnings about GCC extensions. def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, GNUBinaryLiteral, GNUCaseRange, GNUComplexInteger, GNUCompoundLiteralInitializer, GNUConditionalOmittedOperand, GNUDesignator, GNUEmptyInitializer, GNUEmptyStruct, VLAExtension, GNUFlexibleArrayInitializer, GNUFlexibleArrayUnionMember, GNUFoldingConstant, GNUImaginaryConstant, GNULabelsAsValue, RedeclaredClassMember, GNURedeclaredEnum, GNUStatementExpression, GNUStaticFloatInit, GNUStringLiteralOperatorTemplate, GNUUnionCast, GNUVariableSizedTypeNotAtEnd, ZeroLengthArray, GNUZeroLineDirective, GNUZeroVariadicMacroArguments]>; // A warning group for warnings about code that clang accepts but gcc doesn't. def GccCompat : DiagGroup<"gcc-compat">; // A warning group for warnings about Microsoft extensions. def Microsoft : DiagGroup<"microsoft">; def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">; def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">; def ObjCNoPropertyAutoSynthesis : DiagGroup<"objc-property-synthesis">; // ObjC API warning groups. def ObjCRedundantLiteralUse : DiagGroup<"objc-redundant-literal-use">; def ObjCRedundantAPIUse : DiagGroup<"objc-redundant-api-use", [ ObjCRedundantLiteralUse ]>; def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [ ObjCRedundantAPIUse ]>; def ObjCStringComparison : DiagGroup<"objc-string-compare">; def ObjCStringConcatenation : DiagGroup<"objc-string-concatenation">; def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [ ObjCStringComparison ]>; // Inline ASM warnings. def ASMOperandWidths : DiagGroup<"asm-operand-widths">; def ASM : DiagGroup<"asm", [ ASMOperandWidths ]>; // OpenMP warnings. def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">; def OpenMPClauses : DiagGroup<"openmp-clauses">; def OpenMPLoopForm : DiagGroup<"openmp-loop-form">; // Backend warnings. def BackendInlineAsm : DiagGroup<"inline-asm">; def BackendFrameLargerThanEQ : DiagGroup<"frame-larger-than=">; def BackendPlugin : DiagGroup<"backend-plugin">; def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">; def BackendOptimizationRemark : DiagGroup<"pass">; def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">; def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; def BackendOptimizationFailure : DiagGroup<"pass-failed">; // Instrumentation based profiling warnings. def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; // AddressSanitizer frontent instrumentation remarks. def SanitizeAddressRemarks : DiagGroup<"sanitize-address">; // Issues with serialized diagnostics. def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">; // A warning group for warnings about code that clang accepts when // compiling CUDA C/C++ but which is not compatible with the CUDA spec. def CudaCompat : DiagGroup<"cuda-compat">; + +// A warning group for things that will change semantics in the future. +def FutureCompat : DiagGroup<"future-compat">; Index: vendor/clang/dist/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- vendor/clang/dist/include/clang/Basic/DiagnosticParseKinds.td (revision 278753) +++ vendor/clang/dist/include/clang/Basic/DiagnosticParseKinds.td (revision 278754) @@ -1,1006 +1,1010 @@ //==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Parser Diagnostics //===----------------------------------------------------------------------===// let Component = "Parse" in { def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">, CatInlineAsm; def warn_file_asm_volatile : Warning< "meaningless 'volatile' on asm outside function">, CatInlineAsm; let CategoryName = "Inline Assembly Issue" in { def err_asm_empty : Error<"__asm used with no assembly instructions">; def err_inline_ms_asm_parsing : Error<"%0">; def err_msasm_unsupported_arch : Error< "Unsupported architecture '%0' for MS-style inline assembly">; def err_msasm_unable_to_create_target : Error< "MS-style inline assembly is not available: %0">; } let CategoryName = "Parse Issue" in { def ext_empty_translation_unit : Extension< "ISO C requires a translation unit to contain at least one declaration">, InGroup>; def warn_cxx98_compat_top_level_semi : Warning< "extra ';' outside of a function is incompatible with C++98">, InGroup, DefaultIgnore; def ext_extra_semi : Extension< "extra ';' %select{" "outside of a function|" "inside a %1|" "inside instance variable list|" "after member function definition}0">, InGroup; def ext_extra_semi_cxx11 : Extension< "extra ';' outside of a function is a C++11 extension">, InGroup; def warn_extra_semi_after_mem_fn_def : Warning< "extra ';' after member function definition">, InGroup, DefaultIgnore; def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">, InGroup; def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, InGroup; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; def ext_thread_before : Extension<"'__thread' before '%0'">; def ext_keyword_as_ident : ExtWarn< "keyword '%0' will be made available as an identifier " "%select{here|for the remainder of the translation unit}1">, InGroup; def error_empty_enum : Error<"use of empty enum">; def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; def err_invalid_short_spec : Error<"'short %0' is invalid">; def err_invalid_long_spec : Error<"'long %0' is invalid">; def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; def ext_ident_list_in_param : Extension< "type-less parameter names in function declaration">; def ext_c99_variable_decl_in_for_loop : Extension< "variable declaration in for loop is a C99-specific feature">, InGroup; def ext_c99_compound_literal : Extension< "compound literals are a C99-specific feature">, InGroup; def ext_enumerator_list_comma_c : Extension< "commas at the end of enumerator lists are a C99-specific " "feature">, InGroup; def ext_enumerator_list_comma_cxx : Extension< "commas at the end of enumerator lists are a C++11 extension">, InGroup; def warn_cxx98_compat_enumerator_list_comma : Warning< "commas at the end of enumerator lists are incompatible with C++98">, InGroup, DefaultIgnore; def err_enumerator_list_missing_comma : Error< "missing ',' between enumerators">; def err_enumerator_unnamed_no_def : Error< "unnamed enumeration must be a definition">; def ext_cxx11_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a C++11 extension">, InGroup; def ext_c_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a Microsoft extension">, InGroup; def warn_cxx98_compat_enum_fixed_underlying_type : Warning< "enumeration types with a fixed underlying type are incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_alignof : Warning< "alignof expressions are incompatible with C++98">, InGroup, DefaultIgnore; def ext_alignof_expr : ExtWarn< "%0 applied to an expression is a GNU extension">, InGroup; def warn_microsoft_dependent_exists : Warning< "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, InGroup>; def warn_microsoft_qualifiers_ignored : Warning< "qualifiers after comma in declarator list are ignored">, InGroup; def ext_c11_generic_selection : Extension< "generic selections are a C11-specific feature">, InGroup; def err_duplicate_default_assoc : Error< "duplicate default generic association">; def note_previous_default_assoc : Note< "previous default generic association is here">; def ext_c11_alignment : Extension< "%0 is a C11-specific feature">, InGroup; def ext_c11_noreturn : Extension< "_Noreturn functions are a C11-specific feature">, InGroup; def err_c11_noreturn_misplaced : Error< "'_Noreturn' keyword must precede function declarator">; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup; def ext_gnu_address_of_label : Extension< "use of GNU address-of-label extension">, InGroup; def err_stmtexpr_file_scope : Error< "statement expression not allowed at file scope">; def ext_gnu_statement_expr : Extension< "use of GNU statement expression extension">, InGroup; def ext_gnu_conditional_expr : Extension< "use of GNU ?: conditional expression extension, omitting middle operand">, InGroup; def ext_gnu_empty_initializer : Extension< "use of GNU empty initializer extension">, InGroup; def ext_gnu_array_range : Extension<"use of GNU array range extension">, InGroup; def ext_gnu_missing_equal_designator : ExtWarn< "use of GNU 'missing =' extension in designator">, InGroup; def err_expected_equal_designator : Error<"expected '=' or another designator">; def ext_gnu_old_style_field_designator : ExtWarn< "use of GNU old-style field designator extension">, InGroup; def ext_gnu_case_range : Extension<"use of GNU case range extension">, InGroup; // Generic errors. def err_expected_expression : Error<"expected expression">; def err_expected_type : Error<"expected a type">; def err_expected_external_declaration : Error<"expected external declaration">; def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">; def err_expected_semi_declaration : Error< "expected ';' at end of declaration">; def err_expected_semi_decl_list : Error< "expected ';' at end of declaration list">; def ext_expected_semi_decl_list : ExtWarn< "expected ';' at end of declaration list">; def err_expected_member_name_or_semi : Error< "expected member name or ';' after declaration specifiers">; def err_function_declared_typedef : Error< "function definition declared 'typedef'">; def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; def err_at_in_class : Error<"unexpected '@' in member specification">; def err_expected_fn_body : Error< "expected function body after function declarator">; def warn_attribute_on_function_definition : Warning< "GCC does not allow %0 attribute in this position on a function definition">, InGroup; def warn_gcc_attribute_location : Warning< "GCC does not allow an attribute in this position on a function declaration">, InGroup; def warn_attribute_no_decl : Warning< "attribute %0 ignored, because it is not attached to a declaration">, InGroup; def err_expected_method_body : Error<"expected method body">; def err_invalid_token_after_toplevel_declarator : Error< "expected ';' after top level declarator">; def err_invalid_token_after_declarator_suggest_equal : Error< "invalid %0 at end of declaration; did you mean '='?">; def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; def err_expected_rparen_after : Error<"expected ')' after '%0'">; def err_expected_punc : Error<"expected ')' or ',' after '%0'">; def err_expected_less_after : Error<"expected '<' after '%0'">; def err_expected_lbrace_in_compound_literal : Error< "expected '{' in compound literal">; def err_expected_while : Error<"expected 'while' in do/while loop">; def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; def err_expected_semi_after_expr : Error<"expected ';' after expression">; def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; def err_expected_semi_after_method_proto : Error< "expected ';' after method prototype">; def err_expected_semi_after_namespace_name : Error< "expected ';' after namespace name">; def err_unexpected_namespace_attributes_alias : Error< "attributes cannot be specified on namespace alias">; def err_unexpected_nested_namespace_attribute : Error< "attributes cannot be specified on a nested namespace definition">; def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; def err_namespace_nonnamespace_scope : Error< "namespaces can only be defined in global or namespace scope">; def ext_nested_namespace_definition : ExtWarn< "nested namespace definition is a C++1z extension; " "define each namespace separately">, InGroup; def warn_cxx14_compat_nested_namespace_definition : Warning< "nested namespace definition is incompatible with C++ standards before C++1z">, InGroup, DefaultIgnore; def err_inline_nested_namespace_definition : Error< "nested namespace definition cannot be 'inline'">; def err_expected_semi_after_attribute_list : Error< "expected ';' after attribute list">; def err_expected_semi_after_static_assert : Error< "expected ';' after static_assert">; def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; def err_single_decl_assign_in_for_range : Error< "range-based 'for' statement uses ':', not '='">; def warn_missing_selector_name : Warning< "%0 used as the name of the previous parameter rather than as part " "of the selector">, InGroup>; def note_missing_selector_name : Note< "introduce a parameter name to make %0 part of the selector">; def note_force_empty_selector_name : Note< "or insert whitespace before ':' to use %0 as parameter name " "and have an empty entry in the selector">; def err_label_end_of_compound_statement : Error< "label at end of compound statement: expected statement">; def err_address_of_label_outside_fn : Error< "use of address-of-label extension outside of a function body">; def err_asm_operand_wide_string_literal : Error< "cannot use %select{unicode|wide}0 string literal in 'asm'">; def err_expected_selector_for_method : Error< "expected selector for Objective-C method">; def err_expected_property_name : Error<"expected property name">; def err_unexpected_at : Error<"unexpected '@' in program">; def err_atimport : Error< "use of '@import' when modules are disabled">; def err_invalid_reference_qualifier_application : Error< "'%0' qualifier may not be applied to a reference">; def err_illegal_decl_reference_to_reference : Error< "%0 declared as a reference to a reference">; def ext_rvalue_reference : ExtWarn< "rvalue references are a C++11 extension">, InGroup; def warn_cxx98_compat_rvalue_reference : Warning< "rvalue references are incompatible with C++98">, InGroup, DefaultIgnore; def ext_ref_qualifier : ExtWarn< "reference qualifiers on functions are a C++11 extension">, InGroup; def warn_cxx98_compat_ref_qualifier : Warning< "reference qualifiers on functions are incompatible with C++98">, InGroup, DefaultIgnore; def ext_inline_namespace : ExtWarn< "inline namespaces are a C++11 feature">, InGroup; def warn_cxx98_compat_inline_namespace : Warning< "inline namespaces are incompatible with C++98">, InGroup, DefaultIgnore; def ext_generalized_initializer_lists : ExtWarn< "generalized initializer lists are a C++11 extension">, InGroup; def warn_cxx98_compat_generalized_initializer_lists : Warning< "generalized initializer lists are incompatible with C++98">, InGroup, DefaultIgnore; def err_init_list_bin_op : Error<"initializer list cannot be used on the " "%select{left|right}0 hand side of operator '%1'">; def warn_cxx98_compat_trailing_return_type : Warning< "trailing return types are incompatible with C++98">, InGroup, DefaultIgnore; def ext_auto_type_specifier : ExtWarn< "'auto' type specifier is a C++11 extension">, InGroup; def warn_auto_storage_class : Warning< "'auto' storage class specifier is redundant and incompatible with C++11">, InGroup, DefaultIgnore; def ext_auto_storage_class : ExtWarn< "'auto' storage class specifier is not permitted in C++11, and will not " "be supported in future releases">, InGroup>; def ext_decltype_auto_type_specifier : ExtWarn< "'decltype(auto)' type specifier is a C++14 extension">, InGroup; def warn_cxx11_compat_decltype_auto_type_specifier : Warning< "'decltype(auto)' type specifier is incompatible with C++ standards before " "C++14">, InGroup, DefaultIgnore; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup; def warn_cxx98_compat_for_range : Warning< "range-based for loop is incompatible with C++98">, InGroup, DefaultIgnore; def err_for_range_identifier : Error< "range-based for loop requires type for loop variable">; def err_for_range_expected_decl : Error< "for range declaration must declare a variable">; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; def err_missing_comma_before_ellipsis : Error< "C requires a comma prior to the ellipsis in a variadic function type">; def err_unexpected_typedef_ident : Error< "unexpected type name %0: expected identifier">; def warn_cxx98_compat_decltype : Warning< "'decltype' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_unexpected_scope_on_base_decltype : Error< "unexpected namespace scope prior to decltype">; def err_expected_class_name : Error<"expected class name">; def err_expected_class_name_not_template : Error<"'typename' is redundant; base classes are implicitly types">; def err_unspecified_vla_size_with_static : Error< "'static' may not be used with an unspecified variable length array size">; def err_unspecified_size_with_static : Error< "'static' may not be used without an array size">; def warn_deprecated_register : Warning< "'register' storage class specifier is deprecated">, InGroup; def err_expected_parentheses_around_typename : Error< "expected parentheses around type name in %0 expression">; def err_expected_case_before_expression: Error< "expected 'case' keyword before expression">; // Declarations. def err_typename_requires_specqual : Error< "type name requires a specifier or qualifier">; def err_typename_invalid_storageclass : Error< "type name does not allow storage class to be specified">; def err_typename_invalid_functionspec : Error< "type name does not allow function specifier to be specified">; def err_typename_invalid_constexpr : Error< "type name does not allow constexpr specifier to be specified">; def err_typename_identifiers_only : Error< "typename is allowed for identifiers only">; def err_invalid_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier">; def err_invalid_vector_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier. " "'__vector' must be first">; def err_invalid_pixel_decl_spec_combination : Error< "'__pixel' must be preceded by '__vector'. " "'%0' declaration specifier not allowed here">; def err_invalid_vector_bool_decl_spec : Error< "cannot use '%0' with '__vector bool'">; def err_invalid_vector_double_decl_spec : Error < "use of 'double' with '__vector' requires VSX support to be enabled (available on the POWER7 or later)">; def err_invalid_vector_long_double_decl_spec : Error< "cannot use 'long double' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< "Use of 'long' with '__vector' is deprecated">, InGroup; def err_friend_invalid_in_context : Error< "'friend' used outside of class">; def err_use_of_tag_name_without_tag : Error< "must use '%1' tag to refer to type %0%select{| in this scope}2">; def err_templated_using_directive : Error< "cannot template a using directive">; def err_templated_using_declaration : Error< "cannot template a using declaration">; def err_unexpected_colon_in_nested_name_spec : Error< "unexpected ':' in nested name specifier; did you mean '::'?">; def err_unexpected_token_in_nested_name_spec : Error< "'%0' cannot be a part of nested name specifier; did you mean ':'?">; def err_bool_redeclaration : Error< "redeclaration of C++ built-in type 'bool'">; def ext_c11_static_assert : Extension< "_Static_assert is a C11-specific feature">, InGroup; def warn_cxx98_compat_static_assert : Warning< "static_assert declarations are incompatible with C++98">, InGroup, DefaultIgnore; def err_paren_after_colon_colon : Error< "unexpected parenthesis after '::'">; def err_function_definition_not_allowed : Error< "function definition is not allowed here">; def err_expected_end_of_enumerator : Error< "expected '= constant-expression' or end of enumerator definition">; def err_expected_coloncolon_after_super : Error< "expected '::' after '__super'">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< "method type specifier must start with '-' or '+'">; def err_objc_no_attributes_on_category : Error< "attributes may not be specified on a category">; def err_objc_missing_end : Error<"missing '@end'">; def note_objc_container_start : Note< "%select{class|protocol|category|class extension|implementation" "|category implementation}0 started here">; def warn_objc_protocol_qualifier_missing_id : Warning< "protocol has no object type specified; defaults to qualified 'id'">; def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; def err_illegal_super_cast : Error< "cannot cast 'super' (it isn't an expression)">; def err_nsnumber_nonliteral_unary : Error< "@%0 must be followed by a number to form an NSNumber object">; def warn_cstyle_param : Warning< "use of C-style parameters in Objective-C method declarations" " is deprecated">, InGroup; let CategoryName = "ARC Parse Issue" in { def err_arc_bridge_retain : Error< "unknown cast annotation __bridge_retain; did you mean __bridge_retained?">; // To be default mapped to an error later. def warn_arc_bridge_cast_nonarc : Warning< "'%0' casts have no effect when not using ARC">, InGroup>; } def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; def err_objc_expected_equal_for_getter : Error< "expected '=' for Objective-C getter">; def err_objc_expected_equal_for_setter : Error< "expected '=' for Objective-C setter">; def err_objc_expected_selector_for_getter_setter : Error< "expected selector for Objective-C %select{setter|getter}0">; def err_objc_property_requires_field_name : Error< "property requires fields to be named">; def err_objc_property_bitfield : Error<"property name cannot be a bitfield">; def err_objc_expected_property_attr : Error<"unknown property attribute %0">; def err_objc_properties_require_objc2 : Error< "properties are an Objective-C 2 feature">; def err_objc_unexpected_attr : Error< "prefix attribute must be followed by an interface or protocol">; def err_objc_postfix_attribute : Error < "postfix attributes are not allowed on Objective-C directives">; def err_objc_postfix_attribute_hint : Error < "postfix attributes are not allowed on Objective-C directives, place" " them in front of '%select{@interface|@protocol}0'">; def err_objc_directive_only_in_protocol : Error< "directive may only be specified in protocols only">; def err_missing_catch_finally : Error< "@try statement without a @catch and @finally clause">; def err_objc_concat_string : Error<"unexpected token after Objective-C string">; def err_expected_objc_container : Error< "'@end' must appear in an Objective-C context">; def err_unexpected_protocol_qualifier : Error< "@implementation declaration cannot be protocol qualified">; def err_objc_unexpected_atend : Error< "'@end' appears where closing brace '}' is expected">; def error_property_ivar_decl : Error< "property synthesize requires specification of an ivar">; def err_synthesized_property_name : Error< "expected a property name in @synthesize">; def warn_semicolon_before_method_body : Warning< "semicolon before method body is ignored">, InGroup>, DefaultIgnore; def note_extra_comma_message_arg : Note< "comma separating Objective-C messaging arguments">; def err_expected_field_designator : Error< "expected a field designator, such as '.field = 4'">; def err_declaration_does_not_declare_param : Error< "declaration does not declare a parameter">; def err_no_matching_param : Error<"parameter named %0 is missing">; /// C++ parser diagnostics def err_invalid_operator_on_type : Error< "cannot use %select{dot|arrow}0 operator on a type">; def err_expected_unqualified_id : Error< "expected %select{identifier|unqualified-id}0">; def err_brackets_go_after_unqualified_id : Error< "brackets go after the %select{identifier|unqualified-id}0">; def err_unexpected_unqualified_id : Error<"type-id cannot have a name">; def err_func_def_no_params : Error< "function definition does not declare parameters">; def err_expected_lparen_after_type : Error< "expected '(' for function-style cast or type construction">; def err_expected_init_in_condition : Error< "variable declaration in condition must have an initializer">; def err_expected_init_in_condition_lparen : Error< "variable declaration in condition cannot have a parenthesized initializer">; def err_extraneous_rparen_in_condition : Error< "extraneous ')' after condition, expected a statement">; def warn_dangling_else : Warning< "add explicit braces to avoid dangling else">, InGroup; def err_expected_member_or_base_name : Error< "expected class member or base class name">; def err_expected_lbrace_after_base_specifiers : Error< "expected '{' after base class list">; def err_missing_end_of_definition : Error< "missing '}' at end of definition of %q0">; def note_missing_end_of_definition_before : Note< "still within definition of %q0 here">; def ext_ellipsis_exception_spec : Extension< "exception specification of '...' is a Microsoft extension">, InGroup; def err_dynamic_and_noexcept_specification : Error< "cannot have both throw() and noexcept() clause on the same function">; def err_except_spec_unparsed : Error< "unexpected end of exception specification">; def warn_cxx98_compat_noexcept_decl : Warning< "noexcept specifications are incompatible with C++98">, InGroup, DefaultIgnore; def err_expected_catch : Error<"expected catch">; def err_using_namespace_in_class : Error< "'using namespace' is not allowed in classes">; def err_constructor_bad_name : Error< "missing return type for function %0; did you mean the constructor name %1?">; def err_destructor_tilde_identifier : Error< "expected a class name after '~' to name a destructor">; def err_destructor_tilde_scope : Error< "'~' in destructor name should be after nested name specifier">; def err_destructor_template_id : Error< "destructor name %0 does not refer to a template">; def err_default_arg_unparsed : Error< "unexpected end of default argument expression">; def err_bracket_depth_exceeded : Error< "bracket nesting level exceeded maximum of %0">, DefaultFatal; def note_bracket_depth : Note< "use -fbracket-depth=N to increase maximum nesting level">; def err_misplaced_ellipsis_in_declaration : Error< "'...' must %select{immediately precede declared identifier|" "be innermost component of anonymous pack declaration}0">; def warn_misplaced_ellipsis_vararg : Warning< "'...' in this location creates a C-style varargs function" "%select{, not a function parameter pack|}0">, InGroup>; def note_misplaced_ellipsis_vararg_existing_ellipsis : Note< "preceding '...' declares a function parameter pack">; def note_misplaced_ellipsis_vararg_add_ellipsis : Note< "place '...' %select{immediately before declared identifier|here}0 " "to declare a function parameter pack">; def note_misplaced_ellipsis_vararg_add_comma : Note< "insert ',' before '...' to silence this warning">; def ext_abstract_pack_declarator_parens : ExtWarn< "ISO C++11 requires a parenthesized pack declaration to have a name">, InGroup>; def err_function_is_not_record : Error< "unexpected %0 in function call; perhaps remove the %0?">; def err_super_in_using_declaration : Error< "'__super' cannot be used with a using declaration">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading def err_literal_operator_string_prefix : Error< "string literal after 'operator' cannot have an encoding prefix">; def err_literal_operator_string_not_empty : Error< "string literal after 'operator' must be '\"\"'">; def warn_cxx98_compat_literal_operator : Warning< "literal operators are incompatible with C++98">, InGroup, DefaultIgnore; // Classes. def err_anon_type_definition : Error< "declaration of anonymous %0 must be a definition">; def err_default_delete_in_multiple_declaration : Error< "'= %select{default|delete}0' is a function definition and must occur in a " "standalone declaration">; def warn_cxx98_compat_noexcept_expr : Warning< "noexcept expressions are incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_nullptr : Warning< "'nullptr' is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx14_compat_attribute : Warning< "attributes on %select{a namespace|an enumerator}0 declaration are " "incompatible with C++ standards before C++1z">, InGroup, DefaultIgnore; def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_attribute : Warning< "C++11 attribute syntax is incompatible with C++98">, InGroup, DefaultIgnore; def err_cxx11_attribute_forbids_arguments : Error< "attribute %0 cannot have an argument list">; def err_attribute_requires_arguments : Error< "parentheses must be omitted if %0 attribute's argument list is empty">; def err_cxx11_attribute_forbids_ellipsis : Error< "attribute '%0' cannot be used as an attribute pack">; def err_cxx11_attribute_repeated : Error< "attribute %0 cannot appear multiple times in an attribute specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " "introducing an attribute">; def err_ms_declspec_type : Error< "__declspec attributes must be an identifier or string literal">; def err_ms_property_no_getter_or_putter : Error< "property does not specify a getter or a putter">; def err_ms_property_unknown_accessor : Error< "expected 'get' or 'put' in property declaration">; def err_ms_property_has_set_accessor : Error< "putter for property must be specified as 'put', not 'set'">; def err_ms_property_missing_accessor_kind : Error< "missing 'get=' or 'put='">; def err_ms_property_expected_equal : Error< "expected '=' after '%0'">; def err_ms_property_duplicate_accessor : Error< "property declaration specifies '%0' accessor twice">; def err_ms_property_expected_accessor_name : Error< "expected name of accessor method">; def err_ms_property_expected_comma_or_rparen : Error< "expected ',' or ')' at end of property accessor list">; def err_ms_property_initializer : Error< "property declaration cannot have an in-class initializer">; /// C++ Templates def err_expected_template : Error<"expected template">; def err_unknown_template_name : Error< "unknown template name %0">; def err_expected_comma_greater : Error< "expected ',' or '>' in template-parameter-list">; def err_class_on_template_template_param : Error< "template template parameter requires 'class' after the parameter list">; def ext_template_template_param_typename : ExtWarn< "template template parameter using 'typename' is a C++1z extension">, InGroup; def warn_cxx14_compat_template_template_param_typename : Warning< "template template parameter using 'typename' is " "incompatible with C++ standards before C++1z">, InGroup, DefaultIgnore; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function template|" "|refers to a variable template|}1">; def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_two_right_angle_brackets_need_space : Error< "a space is required between consecutive right angle brackets (use '> >')">; def err_right_angle_bracket_equal_needs_space : Error< "a space is required between a right angle bracket and an equals sign " "(use '> =')">; def warn_cxx11_right_shift_in_template_arg : Warning< "use of right-shift operator ('>>') in template argument will require " "parentheses in C++11">, InGroup; def warn_cxx98_compat_two_right_angle_brackets : Warning< "consecutive right angle brackets are incompatible with C++98 (use '> >')">, InGroup, DefaultIgnore; def err_templated_invalid_declaration : Error< "a static_assert declaration cannot be a template">; def err_multiple_template_declarators : Error< "%select{|a template declaration|an explicit template specialization|" "an explicit template instantiation}0 can " "only %select{|declare|declare|instantiate}0 a single entity">; def err_explicit_instantiation_with_definition : Error< "explicit template instantiation cannot have a definition; if this " "definition is meant to be an explicit specialization, add '<>' after the " "'template' keyword">; def err_template_defn_explicit_instantiation : Error< "%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this " "declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">; def err_friend_explicit_instantiation : Error< "friend cannot be declared in an explicit instantiation; if this " "declaration is meant to be a friend declaration, remove the 'template' keyword">; def err_explicit_instantiation_enum : Error< "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; def warn_missing_dependent_template_keyword : ExtWarn< "use 'template' keyword to treat '%0' as a dependent template name">; def ext_extern_template : Extension< "extern templates are a C++11 extension">, InGroup; def warn_cxx98_compat_extern_template : Warning< "extern templates are incompatible with C++98">, InGroup, DefaultIgnore; def warn_static_inline_explicit_inst_ignored : Warning< "ignoring '%select{static|inline}0' keyword on explicit template " "instantiation">, InGroup>; // Constructor template diagnostics. def err_out_of_line_constructor_template_id : Error< "out-of-line constructor for %0 cannot have template arguments">; def err_out_of_line_template_id_names_constructor : Error< "qualified reference to %0 is a constructor name rather than a " "template name wherever a constructor can be declared">; def err_out_of_line_type_names_constructor : Error< "qualified reference to %0 is a constructor name rather than a " "type wherever a constructor can be declared">; def err_expected_qualified_after_typename : Error< "expected a qualified name after 'typename'">; def warn_expected_qualified_after_typename : ExtWarn< "expected a qualified name after 'typename'">; def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-type template">; def err_expected_type_name_after_typename : Error< "expected an identifier or template-id after '::'">; def err_explicit_spec_non_template : Error< "explicit %select{specialization|instantiation}0 of non-template %1 %2">; def err_default_template_template_parameter_not_template : Error< "default template argument for a template template parameter must be a class " "template">; def ext_fold_expression : ExtWarn< "pack fold expression is a C++1z extension">, InGroup; def warn_cxx14_compat_fold_expression : Warning< "pack fold expression is incompatible with C++ standards before C++1z">, InGroup, DefaultIgnore; def err_expected_fold_operator : Error< "expected a foldable binary operator in fold expression">; def err_fold_operator_mismatch : Error< "operators in fold expression must be the same">; def err_ctor_init_missing_comma : Error< "missing ',' between base or member initializers">; // C++ declarations def err_friend_decl_defines_type : Error< "cannot define a type in a friend declaration">; def err_missing_whitespace_digraph : Error< "found '<::' after a " "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0" " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">; def ext_deleted_function : ExtWarn< "deleted function definitions are a C++11 extension">, InGroup; def warn_cxx98_compat_deleted_function : Warning< "deleted function definitions are incompatible with C++98">, InGroup, DefaultIgnore; def ext_defaulted_function : ExtWarn< "defaulted function definitions are a C++11 extension">, InGroup; def warn_cxx98_compat_defaulted_function : Warning< "defaulted function definitions are incompatible with C++98">, InGroup, DefaultIgnore; // C++11 in-class member initialization def ext_nonstatic_member_init : ExtWarn< "in-class initialization of non-static data member is a C++11 extension">, InGroup; def warn_cxx98_compat_nonstatic_member_init : Warning< "in-class initialization of non-static data members is incompatible with C++98">, InGroup, DefaultIgnore; def err_bitfield_member_init: Error< "bitfield member cannot have an in-class initializer">; def err_incomplete_array_member_init: Error< "array bound cannot be deduced from an in-class initializer">; // C++11 alias-declaration def ext_alias_declaration : ExtWarn< "alias declarations are a C++11 extension">, InGroup; def warn_cxx98_compat_alias_declaration : Warning< "alias declarations are incompatible with C++98">, InGroup, DefaultIgnore; def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; def err_alias_declaration_specialization : Error< "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; // C++11 override control def ext_override_control_keyword : ExtWarn< "'%0' keyword is a C++11 extension">, InGroup; def warn_cxx98_compat_override_control_keyword : Warning< "'%0' keyword is incompatible with C++98">, InGroup, DefaultIgnore; def err_override_control_interface : Error< "'%0' keyword not permitted with interface types">; def ext_ms_sealed_keyword : ExtWarn< "'sealed' keyword is a Microsoft extension">, InGroup; def err_access_specifier_interface : Error< "interface types cannot specify '%select{private|protected}0' access">; def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; def err_scoped_enum_missing_identifier : Error< "scoped enumeration requires a name">; def ext_scoped_enum : ExtWarn< "scoped enumerations are a C++11 extension">, InGroup; def warn_cxx98_compat_scoped_enum : Warning< "scoped enumerations are incompatible with C++98">, InGroup, DefaultIgnore; def err_expected_parameter_pack : Error< "expected the name of a parameter pack">; def err_paren_sizeof_parameter_pack : Error< "missing parentheses around the size of parameter pack %0">; def err_sizeof_parameter_pack : Error< "expected parenthesized parameter pack name in 'sizeof...' expression">; // C++11 lambda expressions def err_expected_comma_or_rsquare : Error< "expected ',' or ']' in lambda capture list">; def err_this_captured_by_reference : Error< "'this' cannot be captured by reference">; def err_expected_capture : Error< "expected variable name or 'this' in lambda capture list">; def err_expected_lambda_body : Error<"expected body of lambda expression">; def warn_cxx98_compat_lambda : Warning< "lambda expressions are incompatible with C++98">, InGroup, DefaultIgnore; def err_lambda_missing_parens : Error< "lambda requires '()' before %select{'mutable'|return type|" "attribute specifier}0">; +def warn_init_capture_direct_list_init : Warning< + "direct list initialization of a lambda init-capture will change meaning in " + "a future version of Clang; insert an '=' to avoid a change in behavior">, + InGroup; // Availability attribute def err_expected_version : Error< "expected a version of the form 'major[.minor[.subminor]]'">; def warn_expected_consistent_version_separator : Warning< "use same version number separators '_' or '.'; as in " "'major[.minor[.subminor]]'">, InGroup; def err_zero_version : Error< "version number must have non-zero major, minor, or sub-minor version">; def err_availability_expected_platform : Error< "expected a platform name, e.g., 'macosx'">; // objc_bridge_related attribute def err_objcbridge_related_expected_related_class : Error< "expected a related ObjectiveC class name, e.g., 'NSColor'">; def err_objcbridge_related_selector_name : Error< "expected a class method selector with single argument, e.g., 'colorWithCGColor:'">; def err_availability_expected_change : Error< "expected 'introduced', 'deprecated', or 'obsoleted'">; def err_availability_unknown_change : Error< "%0 is not an availability stage; use 'introduced', 'deprecated', or " "'obsoleted'">; def err_availability_redundant : Error< "redundant %0 availability change; only the last specified change will " "be used">; def warn_availability_and_unavailable : Warning< "'unavailable' availability overrides all other availability information">, InGroup; // Type safety attributes def err_type_safety_unknown_flag : Error< "invalid comparison flag %0; use 'layout_compatible' or 'must_be_null'">; // Type traits def err_type_trait_arity : Error< "type trait requires %0%select{| or more}1 argument%select{|s}2; have " "%3 argument%s3">; // Language specific pragmas // - Generic warnings def warn_pragma_expected_lparen : Warning< "missing '(' after '#pragma %0' - ignoring">, InGroup; def warn_pragma_expected_rparen : Warning< "missing ')' after '#pragma %0' - ignoring">, InGroup; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_section_push_pop_or_name : Warning< "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_section_label_or_name : Warning< "expected a stack label or a string literal for the section name in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_init_seg : Warning< "expected 'compiler', 'lib', 'user', or a string literal for the section name in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_integer : Warning< "expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">, InGroup; def warn_pragma_ms_struct : Warning< "incorrect use of '#pragma ms_struct on|off' - ignored">, InGroup; def warn_pragma_extra_tokens_at_eol : Warning< "extra tokens at end of '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_punc : Warning< "expected ')' or ',' in '#pragma %0'">, InGroup; def warn_pragma_expected_non_wide_string : Warning< "expected non-wide string literal in '#pragma %0'">, InGroup; // - Generic errors def err_pragma_missing_argument : Error< "missing argument to '#pragma %0'%select{|; expected %2}1">; // - #pragma options def warn_pragma_options_expected_align : Warning< "expected 'align' following '#pragma options' - ignored">, InGroup; def warn_pragma_align_expected_equal : Warning< "expected '=' following '#pragma %select{align|options align}0' - ignored">, InGroup; def warn_pragma_align_invalid_option : Warning< "invalid alignment option in '#pragma %select{align|options align}0' - ignored">, InGroup; // - #pragma pack def warn_pragma_unsupported_action : Warning< "known but unsupported action '%1' for '#pragma %0' - ignored">, InGroup; def warn_pragma_invalid_specific_action : Warning< "unknown action '%1' for '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_action_or_r_paren : Warning< "expected action or ')' in '#pragma %0' - ignored">, InGroup; def warn_pragma_invalid_action : Warning< "unknown action for '#pragma %0' - ignored">, InGroup; def warn_pragma_pack_malformed : Warning< "expected integer or identifier in '#pragma pack' - ignored">, InGroup; // - #pragma unused def warn_pragma_unused_expected_var : Warning< "expected '#pragma unused' argument to be a variable name">, InGroup; // - #pragma init_seg def warn_pragma_init_seg_unsupported_target : Warning< "'#pragma init_seg' is only supported when targeting a " "Microsoft environment">, InGroup; // - #pragma fp_contract def err_pragma_fp_contract_scope : Error< "'#pragma fp_contract' can only appear at file scope or at the start of a " "compound statement">; // - #pragma comment def err_pragma_comment_malformed : Error< "pragma comment requires parenthesized identifier and optional string">; def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; // - #pragma detect_mismatch def err_pragma_detect_mismatch_malformed : Error< "pragma detect_mismatch is malformed; it requires two comma-separated " "string literals">; // - #pragma pointers_to_members def err_pragma_pointers_to_members_unknown_kind : Error< "unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1" "'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">; // - #pragma clang optimize on/off def err_pragma_optimize_invalid_argument : Error< "unexpected argument '%0' to '#pragma clang optimize'; " "expected 'on' or 'off'">; def err_pragma_optimize_extra_argument : Error< "unexpected extra argument '%0' to '#pragma clang optimize'">; // OpenCL Section 6.8.g def err_opencl_unknown_type_specifier : Error< "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">; // OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) def warn_pragma_expected_colon : Warning< "missing ':' after %0 - ignoring">, InGroup; def warn_pragma_expected_enable_disable : Warning< "expected 'enable' or 'disable' - ignoring">, InGroup; def warn_pragma_unknown_extension : Warning< "unknown OpenCL extension %0 - ignoring">, InGroup; def err_seh_expected_handler : Error< "expected '__except' or '__finally' block">; def err_seh___except_block : Error< "%0 only allowed in __except block">; def err_seh___except_filter : Error< "%0 only allowed in __except filter expression">; def err_seh___finally_block : Error< "%0 only allowed in __finally block">; // OpenMP support. def warn_pragma_omp_ignored : Warning< "unexpected '#pragma omp ...' in program">, InGroup, DefaultIgnore; def warn_omp_extra_tokens_at_eol : Warning< "extra tokens at the end of '#pragma omp %0' are ignored">, InGroup; def err_omp_unknown_directive : Error< "expected an OpenMP directive">; def err_omp_unexpected_directive : Error< "unexpected OpenMP directive '#pragma omp %0'">; def err_omp_expected_punc : Error< "expected ',' or ')' in '%0' %select{clause|directive}1">; def err_omp_unexpected_clause : Error< "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; def err_omp_more_one_clause : Error< "directive '#pragma omp %0' cannot contain more than one '%1' clause">; def err_omp_immediate_directive : Error< "'#pragma omp %0' cannot be an immediate substatement">; def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; // Pragma loop support. def err_pragma_loop_missing_argument : Error< "missing argument; expected %select{an integer value|" "'%select{enable|full}1' or 'disable'}0">; def err_pragma_loop_invalid_option : Error< "%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, " "vectorize_width, interleave, interleave_count, unroll, or unroll_count">; def err_pragma_invalid_keyword : Error< "invalid argument; expected '%select{enable|full}0' or 'disable'">; // Pragma unroll support. def warn_pragma_unroll_cuda_value_in_parens : Warning< "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">, InGroup; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { def err_module_expected_ident : Error< "expected a module name after module import">; def err_module_expected_semi : Error< "expected ';' after module name">; } } // end of Parser diagnostics Index: vendor/clang/dist/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- vendor/clang/dist/include/clang/Basic/DiagnosticSemaKinds.td (revision 278753) +++ vendor/clang/dist/include/clang/Basic/DiagnosticSemaKinds.td (revision 278754) @@ -1,7489 +1,7493 @@ //==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Semantic Analysis //===----------------------------------------------------------------------===// let Component = "Sema" in { let CategoryName = "Semantic Issue" in { def note_previous_decl : Note<"%0 declared here">; def note_entity_declared_at : Note<"%0 declared here">; def note_callee_decl : Note<"%0 declared here">; def note_defined_here : Note<"%0 defined here">; // For loop analysis def warn_variables_not_in_loop_body : Warning< "variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 " "used in loop condition not modified in loop body">, InGroup, DefaultIgnore; def warn_redundant_loop_iteration : Warning< "variable %0 is %select{decremented|incremented}1 both in the loop header " "and in the loop body">, InGroup, DefaultIgnore; def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">; def warn_duplicate_enum_values : Warning< "element %0 has been implicitly assigned %1 which another element has " "been assigned">, InGroup>, DefaultIgnore; def note_duplicate_element : Note<"element %0 also has value %1">; // Absolute value functions def warn_unsigned_abs : Warning< "taking the absolute value of unsigned type %0 has no effect">, InGroup; def note_remove_abs : Note< "remove the call to '%0' since unsigned values cannot be negative">; def warn_abs_too_small : Warning< "absolute value function %0 given an argument of type %1 but has parameter " "of type %2 which may cause truncation of value">, InGroup; def warn_wrong_absolute_value_type : Warning< "using %select{integer|floating point|complex}1 absolute value function %0 " "when argument is of %select{integer|floating point|complex}2 type">, InGroup; def note_replace_abs_function : Note<"use function '%0' instead">; def warn_infinite_recursive_function : Warning< "all paths through this function will call itself">, InGroup, DefaultIgnore; // Constant expressions def err_expr_not_ice : Error< "expression is not an %select{integer|integral}0 constant expression">; def ext_expr_not_ice : Extension< "expression is not an %select{integer|integral}0 constant expression; " "folding it to a constant is a GNU extension">, InGroup; def err_typecheck_converted_constant_expression : Error< "value of type %0 is not implicitly convertible to %1">; def err_typecheck_converted_constant_expression_disallowed : Error< "conversion from %0 to %1 is not allowed in a converted constant expression">; def err_typecheck_converted_constant_expression_indirect : Error< "conversion from %0 to %1 in converted constant expression would " "bind reference to a temporary">; def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|array size}0 " "is not a constant expression">; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|array size}0 " "%select{cannot be narrowed from type %2 to %3|" "evaluates to %2, which cannot be narrowed to type %3}1">, InGroup, DefaultError, SFINAEFailure; def err_ice_not_integral : Error< "integral constant expression must have integral or unscoped enumeration " "type, not %0">; def err_ice_incomplete_type : Error< "integral constant expression has incomplete class type %0">; def err_ice_explicit_conversion : Error< "integral constant expression requires explicit conversion from %0 to %1">; def note_ice_conversion_here : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_ice_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">, InGroup>; def warn_float_overflow : Warning< "magnitude of floating-point constant too large for type %0; maximum is %1">, InGroup; def warn_float_underflow : Warning< "magnitude of floating-point constant too small for type %0; minimum is %1">, InGroup; def warn_double_const_requires_fp64 : Warning< "double precision constant requires cl_khr_fp64, casting to single precision">; // C99 variable-length arrays def ext_vla : Extension<"variable length arrays are a C99 feature">, InGroup; def warn_vla_used : Warning<"variable length array used">, InGroup, DefaultIgnore; def err_vla_non_pod : Error<"variable length array of non-POD element type %0">; def err_vla_in_sfinae : Error< "variable length array cannot be formed during template argument deduction">; def err_array_star_in_function_definition : Error< "variable length array must be bound in function definition">; def err_vla_decl_in_file_scope : Error< "variable length array declaration not allowed at file scope">; def err_vla_decl_has_static_storage : Error< "variable length array declaration cannot have 'static' storage duration">; def err_vla_decl_has_extern_linkage : Error< "variable length array declaration cannot have 'extern' linkage">; def ext_vla_folded_to_constant : Extension< "variable length array folded to constant array as an extension">, InGroup; // C99 variably modified types def err_variably_modified_template_arg : Error< "variably modified type %0 cannot be used as a template argument">; def err_variably_modified_nontype_template_param : Error< "non-type template parameter of variably modified type %0">; def err_variably_modified_new_type : Error< "'new' cannot allocate object of variably modified type %0">; // C99 Designated Initializers def ext_designated_init : Extension< "designated initializers are a C99 feature">, InGroup; def err_array_designator_negative : Error< "array designator value '%0' is negative">; def err_array_designator_empty_range : Error< "array designator range [%0, %1] is empty">; def err_array_designator_non_array : Error< "array designator cannot initialize non-array type %0">; def err_array_designator_too_large : Error< "array designator index (%0) exceeds array bounds (%1)">; def err_field_designator_non_aggr : Error< "field designator cannot initialize a " "%select{non-struct, non-union|non-class}0 type %1">; def err_field_designator_unknown : Error< "field designator %0 does not refer to any field in type %1">; def err_field_designator_nonfield : Error< "field designator %0 does not refer to a non-static data member">; def note_field_designator_found : Note<"field designator refers here">; def err_designator_for_scalar_init : Error< "designator in initializer for scalar type %0">; def warn_subobject_initializer_overrides : Warning< "subobject initialization overrides initialization of other fields " "within its enclosing subobject">, InGroup; def warn_initializer_overrides : Warning< "initializer overrides prior initialization of this subobject">, InGroup; def note_previous_initializer : Note< "previous initialization %select{|with side effects }0is here" "%select{| (side effects may not occur at run time)}0">; def err_designator_into_flexible_array_member : Error< "designator into flexible array member subobject">; def note_flexible_array_member : Note< "initialized flexible array member %0 is here">; def ext_flexible_array_init : Extension< "flexible array initialization is a GNU extension">, InGroup; // Declarations. def err_bad_variable_name : Error< "%0 cannot be the name of a variable or data member">; def err_bad_parameter_name : Error< "%0 cannot be the name of a parameter">; def err_parameter_name_omitted : Error<"parameter name omitted">; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup, DefaultIgnore; def warn_unused_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_unused_local_typedef : Warning< "unused %select{typedef|type alias}0 %1">, InGroup, DefaultIgnore; def warn_unused_property_backing_ivar : Warning<"ivar %0 which backs the property is not " "referenced in this property's accessor">, InGroup, DefaultIgnore; def warn_unused_const_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_unused_exception_param : Warning<"unused exception parameter %0">, InGroup, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">, InGroup; def warn_redefinition_in_param_list : Warning< "redefinition of %0 will not be visible outside of this function">, InGroup; def warn_empty_parens_are_function_decl : Warning< "empty parentheses interpreted as a function declaration">, InGroup; def warn_parens_disambiguated_as_function_declaration : Warning< "parentheses were disambiguated as a function declaration">, InGroup; def note_additional_parens_for_variable_declaration : Note< "add a pair of parentheses to declare a variable">; def note_empty_parens_function_call : Note< "change this ',' to a ';' to call %0">; def note_empty_parens_default_ctor : Note< "remove parentheses to declare a variable">; def note_empty_parens_zero_initialize : Note< "replace parentheses with an initializer to declare a variable">; def warn_unused_function : Warning<"unused function %0">, InGroup, DefaultIgnore; def warn_unused_member_function : Warning<"unused member function %0">, InGroup, DefaultIgnore; def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, InGroup, DefaultIgnore; def warn_unneeded_internal_decl : Warning< "%select{function|variable}0 %1 is not needed and will not be emitted">, InGroup, DefaultIgnore; def warn_unneeded_static_internal_decl : Warning< "'static' function %0 declared in header file " "should be declared 'static inline'">, InGroup, DefaultIgnore; def warn_unneeded_member_function : Warning< "member function %0 is not needed and will not be emitted">, InGroup, DefaultIgnore; def warn_unused_private_field: Warning<"private field %0 is not used">, InGroup, DefaultIgnore; def warn_parameter_size: Warning< "%0 is a large (%1 bytes) pass-by-value argument; " "pass it by reference instead ?">, InGroup; def warn_return_value_size: Warning< "return value of %0 is a large (%1 bytes) pass-by-value object; " "pass it by reference instead ?">, InGroup; def warn_return_value_udt: Warning< "%0 has C-linkage specified, but returns user-defined type %1 which is " "incompatible with C">, InGroup; def warn_return_value_udt_incomplete: Warning< "%0 has C-linkage specified, but returns incomplete type %1 which could be " "incompatible with C">, InGroup; def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup, DefaultIgnore; def ext_implicit_function_decl : ExtWarn< "implicit declaration of function %0 is invalid in C99">, InGroup; def note_function_suggestion : Note<"did you mean %0?">; def err_ellipsis_first_param : Error< "ISO C requires a named parameter before '...'">; def err_declarator_need_ident : Error<"declarator requires an identifier">; def err_language_linkage_spec_unknown : Error<"unknown linkage language">; def err_language_linkage_spec_not_ascii : Error< "string literal in language linkage specifier cannot have an " "encoding-prefix">; def warn_use_out_of_scope_declaration : Warning< "use of out-of-scope declaration of %0">; def err_inline_non_function : Error< "'inline' can only appear on functions">; def err_noreturn_non_function : Error< "'_Noreturn' can only appear on functions">; def warn_qual_return_type : Warning< "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, InGroup, DefaultIgnore; def warn_decl_shadow : Warning<"declaration shadows a %select{" "local variable|" "variable in %2|" "static data member of %2|" "field of %2}1">, InGroup, DefaultIgnore; // C++ using declarations def err_using_requires_qualname : Error< "using declaration requires a qualified name">; def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; def err_using_dependent_value_is_type : Error< "dependent using declaration resolved to type without 'typename'">; def err_using_decl_nested_name_specifier_is_not_class : Error< "using declaration in class refers into '%0', which is not a class">; def err_using_decl_nested_name_specifier_is_current_class : Error< "using declaration refers to its own class">; def err_using_decl_nested_name_specifier_is_not_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; def err_using_decl_constructor_not_in_direct_base : Error< "%0 is not a direct base of %1, cannot inherit constructors">; def err_using_decl_constructor_conflict : Error< "cannot inherit constructor, already inherited constructor with " "the same signature">; def note_using_decl_constructor_conflict_current_ctor : Note< "conflicting constructor">; def note_using_decl_constructor_conflict_previous_ctor : Note< "previous constructor">; def note_using_decl_constructor_conflict_previous_using : Note< "previously inherited here">; def warn_using_decl_constructor_ellipsis : Warning< "inheriting constructor does not inherit ellipsis">, InGroup>; def note_using_decl_constructor_ellipsis : Note< "constructor declared with ellipsis here">; def err_using_decl_can_not_refer_to_class_member : Error< "using declaration cannot refer to class member">; def note_using_decl_class_member_workaround : Note< "use %select{an alias declaration|a typedef declaration|a reference}0 " "instead">; def err_using_decl_can_not_refer_to_namespace : Error< "using declaration cannot refer to namespace">; def err_using_decl_constructor : Error< "using declaration cannot refer to a constructor">; def warn_cxx98_compat_using_decl_constructor : Warning< "inheriting constructors are incompatible with C++98">, InGroup, DefaultIgnore; def err_using_decl_destructor : Error< "using declaration cannot refer to a destructor">; def err_using_decl_template_id : Error< "using declaration cannot refer to a template specialization">; def note_using_decl_target : Note<"target of using declaration">; def note_using_decl_conflict : Note<"conflicting declaration">; def err_using_decl_redeclaration : Error<"redeclaration of using decl">; def err_using_decl_conflict : Error< "target of using declaration conflicts with declaration already in scope">; def err_using_decl_conflict_reverse : Error< "declaration conflicts with target of using declaration already in scope">; def note_using_decl : Note<"%select{|previous }0using declaration">; def warn_access_decl_deprecated : Warning< "access declarations are deprecated; use using declarations instead">, InGroup; def err_access_decl : Error< "ISO C++11 does not allow access declarations; " "use using declarations instead">; def warn_exception_spec_deprecated : Warning< "dynamic exception specifications are deprecated">, InGroup, DefaultIgnore; def note_exception_spec_deprecated : Note<"use '%0' instead">; def warn_deprecated_copy_operation : Warning< "definition of implicit copy %select{constructor|assignment operator}1 " "for %0 is deprecated because it has a user-declared " "%select{copy %select{assignment operator|constructor}1|destructor}2">, InGroup, DefaultIgnore; def warn_global_constructor : Warning< "declaration requires a global constructor">, InGroup, DefaultIgnore; def warn_global_destructor : Warning< "declaration requires a global destructor">, InGroup, DefaultIgnore; def warn_exit_time_destructor : Warning< "declaration requires an exit-time destructor">, InGroup, DefaultIgnore; def err_invalid_thread : Error< "'%0' is only allowed on variable declarations">; def err_thread_non_global : Error< "'%0' variables must have global storage">; def err_thread_unsupported : Error< "thread-local storage is not supported for the current target">; def warn_maybe_falloff_nonvoid_function : Warning< "control may reach end of non-void function">, InGroup; def warn_falloff_nonvoid_function : Warning< "control reaches end of non-void function">, InGroup; def err_maybe_falloff_nonvoid_block : Error< "control may reach end of non-void block">; def err_falloff_nonvoid_block : Error< "control reaches end of non-void block">; def warn_suggest_noreturn_function : Warning< "%select{function|method}0 %1 could be declared with attribute 'noreturn'">, InGroup, DefaultIgnore; def warn_suggest_noreturn_block : Warning< "block could be declared with attribute 'noreturn'">, InGroup, DefaultIgnore; // Unreachable code. def warn_unreachable : Warning< "code will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_break : Warning< "'break' will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_return : Warning< "'return' will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_loop_increment : Warning< "loop will run at most once (loop increment never executed)">, InGroup, DefaultIgnore; def note_unreachable_silence : Note< "silence by adding parentheses to mark code as explicitly dead">; /// Built-in functions. def ext_implicit_lib_function_decl : ExtWarn< "implicitly declaring library function '%0' with type %1">; def note_include_header_or_declare : Note< "include the header <%0> or explicitly provide a declaration for '%1'">; def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; def warn_implicit_decl_requires_sysheader : Warning< "declaration of built-in function '%1' requires inclusion of the header <%0>">, InGroup; def warn_redecl_library_builtin : Warning< "incompatible redeclaration of library function %0">, InGroup>; def err_builtin_definition : Error<"definition of builtin function %0">; def warn_builtin_unknown : Warning<"use of unknown builtin %0">, InGroup, DefaultError; def warn_dyn_class_memaccess : Warning< "%select{destination for|source of|first operand of|second operand of}0 this " "%1 call is a pointer to %select{|class containing a }2dynamic class %3; " "vtable pointer will be %select{overwritten|copied|moved|compared}4">, InGroup>; def note_bad_memaccess_silence : Note< "explicitly cast the pointer to silence this warning">; def warn_sizeof_pointer_expr_memaccess : Warning< "'%0' call operates on objects of type %1 while the size is based on a " "different type %2">, InGroup; def warn_sizeof_pointer_expr_memaccess_note : Note< "did you mean to %select{dereference the argument to 'sizeof' (and multiply " "it by the number of elements)|remove the addressof in the argument to " "'sizeof' (and multiply it by the number of elements)|provide an explicit " "length}0?">; def warn_sizeof_pointer_type_memaccess : Warning< "argument to 'sizeof' in %0 call is the same pointer type %1 as the " "%select{destination|source}2; expected %3 or an explicit length">, InGroup; def warn_strlcpycat_wrong_size : Warning< "size argument in %0 call appears to be size of the source; " "expected the size of the destination">, InGroup>; def note_strlcpycat_wrong_size : Note< "change size argument to be the size of the destination">; def warn_memsize_comparison : Warning< "size argument in %0 call is a comparison">, InGroup>; def note_memsize_comparison_paren : Note< "did you mean to compare the result of %0 instead?">; def note_memsize_comparison_cast_silence : Note< "explicitly cast the argument to size_t to silence this warning">; def warn_strncat_large_size : Warning< "the value of the size argument in 'strncat' is too large, might lead to a " "buffer overflow">, InGroup; def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " "to be size of the source">, InGroup; def warn_strncat_wrong_size : Warning< "the value of the size argument to 'strncat' is wrong">, InGroup; def note_strncat_wrong_size : Note< "change the argument to be the free space in the destination buffer minus " "the terminating null byte">; def warn_assume_side_effects : Warning< "the argument to %0 has side effects that will be discarded">, InGroup>; def warn_memcpy_chk_overflow : Warning< "%0 will always overflow destination buffer">, InGroup>; /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, InGroup
; def err_static_main : Error<"'main' is not allowed to be declared static">; def err_inline_main : Error<"'main' is not allowed to be declared inline">; def ext_noreturn_main : ExtWarn< "'main' is not allowed to be declared _Noreturn">, InGroup
; def note_main_remove_noreturn : Note<"remove '_Noreturn'">; def err_constexpr_main : Error< "'main' is not allowed to be declared constexpr">; def err_deleted_main : Error<"'main' is not allowed to be deleted">; def err_mainlike_template_decl : Error<"%0 cannot be a template">; def err_main_returns_nonint : Error<"'main' must return 'int'">; def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">, InGroup; def note_main_change_return_type : Note<"change return type to 'int'">; def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " "must be 0, 2, or 3">; def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">, InGroup
; def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 " "parameter of 'main' (%select{argument count|argument array|environment|" "platform-specific data}0) must be of type %1">; def ext_main_used : Extension< "ISO C++ does not allow 'main' to be used by a program">, InGroup
; /// parser diagnostics def ext_no_declarators : ExtWarn<"declaration does not declare anything">, InGroup; def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">, InGroup; def err_typedef_not_identifier : Error<"typedef name must be an identifier">; def err_typedef_changes_linkage : Error<"unsupported: typedef changes linkage" " of anonymous type, but linkage was already computed">; def note_typedef_changes_linkage : Note<"use a tag name here to establish " "linkage prior to definition">; def err_statically_allocated_object : Error< "interface type cannot be statically allocated">; def err_object_cannot_be_passed_returned_by_value : Error< "interface type %1 cannot be %select{returned|passed}0 by value" "; did you forget * in %1?">; def err_parameters_retval_cannot_have_fp16_type : Error< "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; def err_opencl_half_load_store : Error< "%select{loading directly from|assigning directly to}0 pointer to type %1 is not allowed">; def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">; def err_opencl_half_declaration : Error< "declaring variable of type %0 is not allowed">; def err_opencl_half_param : Error< "declaring function parameter of type %0 is not allowed; did you forget * ?">; def err_opencl_half_return : Error< "declaring function return value of type %0 is not allowed; did you forget * ?">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_options_align_reset_failed : Warning< "#pragma options align=reset failed: %0">, InGroup; def err_pragma_options_align_mac68k_target_unsupported : Error< "mac68k alignment pragma is not supported on this target">; def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, InGroup; // Follow the MSVC implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; def warn_pragma_pack_pop_identifer_and_alignment : Warning< "specifying both a name and alignment to 'pop' is undefined">; def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, InGroup; def warn_cxx_ms_struct : Warning<"ms_struct may not produce MSVC-compatible layouts for classes " "with base classes or virtual functions">, DefaultError, InGroup; def err_section_conflict : Error<"%0 causes a section type conflict with %1">; def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; def err_invalid_super_scope : Error<"invalid use of '__super', " "this keyword can only be used inside class or member function scope">; def err_super_in_lambda_unsupported : Error< "use of '__super' inside a lambda is unsupported">; def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, InGroup; def warn_pragma_unused_expected_var_arg : Warning< "only variables can be arguments to '#pragma unused'">, InGroup; def err_pragma_push_visibility_mismatch : Error< "#pragma visibility push with no matching #pragma visibility pop">; def note_surrounding_namespace_ends_here : Note< "surrounding namespace with visibility attribute ends here">; def err_pragma_pop_visibility_mismatch : Error< "#pragma visibility pop with no matching #pragma visibility push">; def note_surrounding_namespace_starts_here : Note< "surrounding namespace with visibility attribute starts here">; def err_pragma_loop_invalid_argument_type : Error< "invalid argument of type %0; expected an integer type">; def err_pragma_loop_invalid_argument_value : Error< "%select{invalid value '%0'; must be positive|value '%0' is too large}1">; def err_pragma_loop_compatibility : Error< "%select{incompatible|duplicate}0 directives '%1' and '%2'">; def err_pragma_loop_precedes_nonloop : Error< "expected a for, while, or do-while loop to follow '%0'">; /// Objective-C parser diagnostics def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; def err_undef_superclass : Error< "cannot find interface declaration for %0, superclass of %1">; def err_forward_superclass : Error< "attempting to use the forward class %0 as superclass of %1">; def err_no_nsconstant_string_class : Error< "cannot find interface declaration for %0">; def err_recursive_superclass : Error< "trying to recursively use %0 as superclass of %1">; def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; def warn_undef_interface : Warning<"cannot find interface declaration for %0">; def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">; def err_protocol_has_circular_dependency : Error< "protocol has circular dependency">; def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; def warn_atprotocol_protocol : Warning< "@protocol is using a forward protocol declaration of %0">, InGroup; def warn_readonly_property : Warning< "attribute 'readonly' of property %0 restricts attribute " "'readwrite' of property inherited from %1">, InGroup; def warn_property_attribute : Warning< "'%1' attribute on property %0 does not match the property inherited from %2">, InGroup; def warn_property_types_are_incompatible : Warning< "property type %0 is incompatible with type %1 inherited from %2">, InGroup>; def warn_protocol_property_mismatch : Warning< "property of type %0 was selected for synthesis">, InGroup>; def err_undef_interface : Error<"cannot find interface declaration for %0">; def err_category_forward_interface : Error< "cannot define %select{category|class extension}0 for undefined class %1">; def err_class_extension_after_impl : Error< "cannot declare class extension for %0 after class implementation">; def note_implementation_declared : Note< "class implementation is declared here">; def note_while_in_implementation : Note< "detected while default synthesizing properties in class implementation">; def note_class_declared : Note< "class is declared here">; def note_receiver_class_declared : Note< "receiver is instance of class declared here">; def note_receiver_expr_here : Note< "receiver expression is here">; def note_receiver_is_id : Note< "receiver is treated with 'id' type for purpose of method lookup">; def note_suppressed_class_declare : Note< "class with specified objc_requires_property_definitions attribute is declared here">; def err_objc_root_class_subclass : Error< "objc_root_class attribute may only be specified on a root class declaration">; def warn_objc_root_class_missing : Warning< "class %0 defined without specifying a base class">, InGroup; def note_objc_needs_superclass : Note< "add a super class to fix this problem">; def warn_dup_category_def : Warning< "duplicate definition of category %1 on interface %0">; def err_conflicting_super_class : Error<"conflicting super class name %0">; def err_dup_implementation_class : Error<"reimplementation of class %0">; def err_dup_implementation_category : Error< "reimplementation of category %1 for class %0">; def err_conflicting_ivar_type : Error< "instance variable %0 has conflicting type%diff{: $ vs $|}1,2">; def err_duplicate_ivar_declaration : Error< "instance variable is already declared">; def warn_on_superclass_use : Warning< "class implementation may not have super class">; def err_conflicting_ivar_bitwidth : Error< "instance variable %0 has conflicting bit-field width">; def err_conflicting_ivar_name : Error< "conflicting instance variable names: %0 vs %1">; def err_inconsistent_ivar_count : Error< "inconsistent number of instance variables specified">; def warn_undef_method_impl : Warning<"method definition for %0 not found">, InGroup>; def warn_conflicting_overriding_ret_types : Warning< "conflicting return type in " "declaration of %0%diff{: $ vs $|}1,2">, InGroup, DefaultIgnore; def warn_conflicting_ret_types : Warning< "conflicting return type in " "implementation of %0%diff{: $ vs $|}1,2">, InGroup; def warn_conflicting_overriding_ret_type_modifiers : Warning< "conflicting distributed object modifiers on return type " "in declaration of %0">, InGroup, DefaultIgnore; def warn_conflicting_ret_type_modifiers : Warning< "conflicting distributed object modifiers on return type " "in implementation of %0">, InGroup; def warn_non_covariant_overriding_ret_types : Warning< "conflicting return type in " "declaration of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_non_covariant_ret_types : Warning< "conflicting return type in " "implementation of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_conflicting_overriding_param_types : Warning< "conflicting parameter types in " "declaration of %0%diff{: $ vs $|}1,2">, InGroup, DefaultIgnore; def warn_conflicting_param_types : Warning< "conflicting parameter types in " "implementation of %0%diff{: $ vs $|}1,2">, InGroup; def warn_conflicting_param_modifiers : Warning< "conflicting distributed object modifiers on parameter type " "in implementation of %0">, InGroup; def warn_conflicting_overriding_param_modifiers : Warning< "conflicting distributed object modifiers on parameter type " "in declaration of %0">, InGroup, DefaultIgnore; def warn_non_contravariant_overriding_param_types : Warning< "conflicting parameter types in " "declaration of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_non_contravariant_param_types : Warning< "conflicting parameter types in " "implementation of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_conflicting_overriding_variadic :Warning< "conflicting variadic declaration of method and its " "implementation">, InGroup, DefaultIgnore; def warn_conflicting_variadic :Warning< "conflicting variadic declaration of method and its " "implementation">; def warn_category_method_impl_match:Warning< "category is implementing a method which will also be implemented" " by its primary class">, InGroup; def warn_implements_nscopying : Warning< "default assign attribute on property %0 which implements " "NSCopying protocol is not appropriate with -fobjc-gc[-only]">; def warn_multiple_method_decl : Warning<"multiple methods named %0 found">, InGroup; def warn_strict_multiple_method_decl : Warning< "multiple methods named %0 found">, InGroup, DefaultIgnore; def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; def not_conv_function_declared_at : Note<"type conversion function declared here">; def note_method_declared_at : Note<"method %0 declared here">; def note_property_attribute : Note<"property %0 is declared " "%select{deprecated|unavailable}1 here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_duplicate_method_decl : Warning<"multiple declarations of method %0 found and ignored">, InGroup, DefaultIgnore; def warn_objc_cdirective_format_string : Warning<"using %0 directive in %select{NSString|CFString}1 " "which is being passed as a formatting argument to the formatting " "%select{method|CFfunction}2">, InGroup, DefaultIgnore; def err_objc_var_decl_inclass : Error<"cannot declare variable inside @interface or @protocol">; def error_missing_method_context : Error< "missing context for method declaration">; def err_objc_property_attr_mutually_exclusive : Error< "property attributes '%0' and '%1' are mutually exclusive">; def err_objc_property_requires_object : Error< "property with '%0' attribute must be of object type">; def warn_objc_property_no_assignment_attribute : Warning< "no 'assign', 'retain', or 'copy' attribute is specified - " "'assign' is assumed">, InGroup; def warn_objc_isa_use : Warning< "direct access to Objective-C's isa is deprecated in favor of " "object_getClass()">, InGroup; def warn_objc_isa_assign : Warning< "assignment to Objective-C's isa is deprecated in favor of " "object_setClass()">, InGroup; def warn_objc_pointer_masking : Warning< "bitmasking for introspection of Objective-C object pointers is strongly " "discouraged">, InGroup; def warn_objc_pointer_masking_performSelector : Warning, InGroup; def warn_objc_property_default_assign_on_object : Warning< "default property attribute 'assign' not appropriate for non-GC object">, InGroup; def warn_property_attr_mismatch : Warning< "property attribute in class extension does not match the primary class">, InGroup; def warn_property_implicitly_mismatched : Warning < "primary property declaration is implicitly strong while redeclaration " "in class extension is weak">, InGroup>; def warn_objc_property_copy_missing_on_block : Warning< "'copy' attribute must be specified for the block property " "when -fobjc-gc-only is specified">; def warn_objc_property_retain_of_block : Warning< "retain'ed block property does not copy the block " "- use copy attribute instead">, InGroup; def warn_objc_readonly_property_has_setter : Warning< "setter cannot be specified for a readonly property">, InGroup; def warn_atomic_property_rule : Warning< "writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 " "with a user defined %select{getter|setter}2">, InGroup>; def note_atomic_property_fixup_suggest : Note<"setter and getter must both be " "synthesized, or both be user defined,or the property must be nonatomic">; def err_atomic_property_nontrivial_assign_op : Error< "atomic property of reference type %0 cannot have non-trivial assignment" " operator">; def warn_cocoa_naming_owned_rule : Warning< "property follows Cocoa naming" " convention for returning 'owned' objects">, InGroup>; def warn_auto_synthesizing_protocol_property :Warning< "auto property synthesis will not synthesize property %0" " declared in protocol %1">, InGroup>; def warn_no_autosynthesis_shared_ivar_property : Warning < "auto property synthesis will not synthesize property " "%0 because it cannot share an ivar with another synthesized property">, InGroup; def warn_no_autosynthesis_property : Warning< "auto property synthesis will not synthesize property " "%0 because it is 'readwrite' but it will be synthesized 'readonly' " "via another property">, InGroup; def warn_autosynthesis_property_in_superclass : Warning< "auto property synthesis will not synthesize property " "%0; it will be implemented by its superclass, use @dynamic to " "acknowledge intention">, InGroup; def warn_autosynthesis_property_ivar_match :Warning< "autosynthesized property %0 will use %select{|synthesized}1 instance variable " "%2, not existing instance variable %3">, InGroup>; def warn_missing_explicit_synthesis : Warning < "auto property synthesis is synthesizing property not explicitly synthesized">, InGroup>, DefaultIgnore; def warn_property_getter_owning_mismatch : Warning< "property declared as returning non-retained objects" "; getter returning retained objects">; def error_property_setter_ambiguous_use : Error< "synthesized properties %0 and %1 both claim setter %2 -" " use of this setter will cause unexpected behavior">; def err_cocoa_naming_owned_rule : Error< "property follows Cocoa naming" " convention for returning 'owned' objects">; def warn_default_atomic_custom_getter_setter : Warning< "atomic by default property %0 has a user defined %select{getter|setter}1 " "(property should be marked 'atomic' if this is intended)">, InGroup, DefaultIgnore; def err_use_continuation_class : Error< "illegal redeclaration of property in class extension %0" " (attribute must be 'readwrite', while its primary must be 'readonly')">; def err_type_mismatch_continuation_class : Error< "type of property %0 in class extension does not match " "property type in primary class">; def err_use_continuation_class_redeclaration_readwrite : Error< "illegal redeclaration of 'readwrite' property in class extension %0" " (perhaps you intended this to be a 'readwrite' redeclaration of a " "'readonly' public property?)">; def err_continuation_class : Error<"class extension has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< "missing context for property implementation declaration">; def error_bad_property_decl : Error< "property implementation must have its declaration in interface %0">; def error_category_property : Error< "property declared in category %0 cannot be implemented in " "class implementation">; def note_property_declare : Note< "property declared here">; def note_protocol_property_declare : Note< "it could also be property of type %0 declared here">; def note_property_synthesize : Note< "property synthesized here">; def error_synthesize_category_decl : Error< "@synthesize not allowed in a category's implementation">; def error_reference_property : Error< "property of reference type is not supported">; def error_missing_property_interface : Error< "property implementation in a category with no category declaration">; def error_bad_category_property_decl : Error< "property implementation must have its declaration in the category %0">; def error_bad_property_context : Error< "property implementation must be in a class or category implementation">; def error_missing_property_ivar_decl : Error< "synthesized property %0 must either be named the same as a compatible" " instance variable or must explicitly name an instance variable">; def error_synthesize_weak_non_arc_or_gc : Error< "@synthesize of 'weak' property is only allowed in ARC or GC mode">; def err_arc_perform_selector_retains : Error< "performSelector names a selector which retains the object">; def warn_arc_perform_selector_leaks : Warning< "performSelector may cause a leak because its selector is unknown">, InGroup>; def warn_dealloc_in_category : Warning< "-dealloc is being overridden in a category">, InGroup; def err_gc_weak_property_strong_type : Error< "weak attribute declared on a __strong type property in GC mode">; def warn_receiver_is_weak : Warning < "weak %select{receiver|property|implicit property}0 may be " "unpredictably set to nil">, InGroup>, DefaultIgnore; def note_arc_assign_to_strong : Note< "assign the value to a strong variable to keep the object alive during use">; def warn_arc_repeated_use_of_weak : Warning < "weak %select{variable|property|implicit property|instance variable}0 %1 is " "accessed multiple times in this %select{function|method|block|lambda}2 " "but may be unpredictably set to nil; assign to a strong variable to keep " "the object alive">, InGroup, DefaultIgnore; def warn_implicitly_retains_self : Warning < "block implicitly retains 'self'; explicitly mention 'self' to indicate " "this is intended behavior">, InGroup>, DefaultIgnore; def warn_arc_possible_repeated_use_of_weak : Warning < "weak %select{variable|property|implicit property|instance variable}0 %1 may " "be accessed multiple times in this %select{function|method|block|lambda}2 " "and may be unpredictably set to nil; assign to a strong variable to keep " "the object alive">, InGroup, DefaultIgnore; def note_arc_weak_also_accessed_here : Note< "also accessed here">; def err_incomplete_synthesized_property : Error< "cannot synthesize property %0 with incomplete type %1">; def error_property_ivar_type : Error< "type of property %0 (%1) does not match type of instance variable %2 (%3)">; def error_property_accessor_type : Error< "type of property %0 (%1) does not match type of accessor %2 (%3)">; def error_ivar_in_superclass_use : Error< "property %0 attempting to use instance variable %1 declared in super class %2">; def error_weak_property : Error< "existing instance variable %1 for __weak property %0 must be __weak">; def error_strong_property : Error< "existing instance variable %1 for strong property %0 may not be __weak">; def error_dynamic_property_ivar_decl : Error< "dynamic property cannot have instance variable specification">; def error_duplicate_ivar_use : Error< "synthesized properties %0 and %1 both claim instance variable %2">; def error_property_implemented : Error<"property %0 is already implemented">; def warn_objc_missing_super_call : Warning< "method possibly missing a [super %0] call">, InGroup; def error_dealloc_bad_result_type : Error< "dealloc return type must be correctly specified as 'void' under ARC, " "instead of %0">; def warn_undeclared_selector : Warning< "undeclared selector %0">, InGroup, DefaultIgnore; def warn_undeclared_selector_with_typo : Warning< "undeclared selector %0; did you mean %1?">, InGroup, DefaultIgnore; def warn_implicit_atomic_property : Warning< "property is assumed atomic by default">, InGroup, DefaultIgnore; def note_auto_readonly_iboutlet_fixup_suggest : Note< "property should be changed to be readwrite">; def warn_auto_readonly_iboutlet_property : Warning< "readonly IBOutlet property %0 when auto-synthesized may " "not work correctly with 'nib' loader">, InGroup>; def warn_auto_implicit_atomic_property : Warning< "property is assumed atomic when auto-synthesizing the property">, InGroup, DefaultIgnore; def warn_unimplemented_selector: Warning< "no method with selector %0 is implemented in this translation unit">, InGroup, DefaultIgnore; def warn_unimplemented_protocol_method : Warning< "method %0 in protocol %1 not implemented">, InGroup; def warning_multiple_selectors: Warning< "several methods with selector %0 of mismatched types are found " "for the @selector expression">, InGroup, DefaultIgnore; // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; def ext_static_assert_no_message : ExtWarn< "static_assert with no message is a C++1z extension">, InGroup; def warn_cxx14_compat_static_assert_no_message : Warning< "static_assert with no message is incompatible with C++ standards before C++1z">, DefaultIgnore, InGroup; def warn_inline_namespace_reopened_noninline : Warning< "inline namespace cannot be reopened as a non-inline namespace">; def err_inline_namespace_mismatch : Error< "%select{|non-}0inline namespace " "cannot be reopened as %select{non-|}0inline">; def err_unexpected_friend : Error< "friends can only be classes or functions">; def ext_enum_friend : ExtWarn< "befriending enumeration type %0 is a C++11 extension">, InGroup; def warn_cxx98_compat_enum_friend : Warning< "befriending enumeration type %0 is incompatible with C++98">, InGroup, DefaultIgnore; def ext_nonclass_type_friend : ExtWarn< "non-class friend type %0 is a C++11 extension">, InGroup; def warn_cxx98_compat_nonclass_type_friend : Warning< "non-class friend type %0 is incompatible with C++98">, InGroup, DefaultIgnore; def err_friend_is_member : Error< "friends cannot be members of the declaring class">; def warn_cxx98_compat_friend_is_member : Warning< "friend declaration naming a member of the declaring class is incompatible " "with C++98">, InGroup, DefaultIgnore; def ext_unelaborated_friend_type : ExtWarn< "unelaborated friend declaration is a C++11 extension; specify " "'%select{struct|interface|union|class|enum}0' to befriend %1">, InGroup; def warn_cxx98_compat_unelaborated_friend_type : Warning< "befriending %1 without '%select{struct|interface|union|class|enum}0' " "keyword is incompatible with C++98">, InGroup, DefaultIgnore; def err_qualified_friend_not_found : Error< "no function named %0 with type %1 was found in the specified scope">; def err_introducing_special_friend : Error< "must use a qualified name when declaring a %select{constructor|" "destructor|conversion operator}0 as a friend">; def err_tagless_friend_type_template : Error< "friend type templates must use an elaborated type">; def err_no_matching_local_friend : Error< "no matching function found in local scope">; def err_no_matching_local_friend_suggest : Error< "no matching function %0 found in local scope; did you mean %3?">; def err_partial_specialization_friend : Error< "partial specialization cannot be declared as a friend">; def err_qualified_friend_def : Error< "friend function definition cannot be qualified with '%0'">; def err_friend_def_in_local_class : Error< "friend function cannot be defined in a local class">; def err_friend_not_first_in_declaration : Error< "'friend' must appear first in a non-function declaration">; def err_using_decl_friend : Error< "cannot befriend target of using declaration">; def warn_template_qualified_friend_unsupported : Warning< "dependent nested name specifier '%0' for friend class declaration is " "not supported; turning off access control for %1">, InGroup; def warn_template_qualified_friend_ignored : Warning< "dependent nested name specifier '%0' for friend template declaration is " "not supported; ignoring this friend declaration">, InGroup; def ext_friend_tag_redecl_outside_namespace : ExtWarn< "unqualified friend declaration referring to type outside of the nearest " "enclosing namespace is a Microsoft extension; add a nested name specifier">, InGroup; def err_invalid_member_in_interface : Error< "%select{data member |non-public member function |static member function |" "user-declared constructor|user-declared destructor|operator |" "nested class }0%1 is not permitted within an interface type">; def err_invalid_base_in_interface : Error< "interface type cannot inherit from " "%select{'struct|non-public 'interface|'class}0 %1'">; def err_abstract_type_in_decl : Error< "%select{return|parameter|variable|field|instance variable|" "synthesized instance variable}0 type %1 is an abstract class">; def err_allocation_of_abstract_type : Error< "allocating an object of abstract class type %0">; def err_throw_abstract_type : Error< "cannot throw an object of abstract type %0">; def err_array_of_abstract_type : Error<"array of abstract class type %0">; def err_capture_of_abstract_type : Error< "by-copy capture of value of abstract type %0">; def err_capture_of_incomplete_type : Error< "by-copy capture of variable %0 with incomplete type %1">; def err_capture_default_non_local : Error< "non-local lambda expression cannot have a capture-default">; def err_multiple_final_overriders : Error< "virtual function %q0 has more than one final overrider in %1">; def note_final_overrider : Note<"final overrider of %q0 in %1">; def err_type_defined_in_type_specifier : Error< "%0 cannot be defined in a type specifier">; def err_type_defined_in_result_type : Error< "%0 cannot be defined in the result type of a function">; def err_type_defined_in_param_type : Error< "%0 cannot be defined in a parameter type">; def err_type_defined_in_alias_template : Error< "%0 cannot be defined in a type alias template">; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; def err_deleted_override : Error< "deleted function %0 cannot override a non-deleted function">; def err_non_deleted_override : Error< "non-deleted function %0 cannot override a deleted function">; def warn_weak_vtable : Warning< "%0 has no out-of-line virtual method definitions; its vtable will be " "emitted in every translation unit">, InGroup>, DefaultIgnore; def warn_weak_template_vtable : Warning< "explicit template instantiation %0 will emit a vtable in every " "translation unit">, InGroup>, DefaultIgnore; def ext_using_undefined_std : ExtWarn< "using directive refers to implicitly-defined namespace 'std'">; // C++ exception specifications def err_exception_spec_in_typedef : Error< "exception specifications are not allowed in %select{typedefs|type aliases}0">; def err_distant_exception_spec : Error< "exception specifications are not allowed beyond a single level " "of indirection">; def err_incomplete_in_exception_spec : Error< "%select{|pointer to |reference to }0incomplete type %1 is not allowed " "in exception specification">; def err_rref_in_exception_spec : Error< "rvalue reference type %0 is not allowed in exception specification">; def err_mismatched_exception_spec : Error< "exception specification in declaration does not match previous declaration">; def ext_mismatched_exception_spec : ExtWarn< "exception specification in declaration does not match previous declaration">, InGroup; def err_override_exception_spec : Error< "exception specification of overriding function is more lax than " "base version">; def ext_override_exception_spec : ExtWarn< "exception specification of overriding function is more lax than " "base version">, InGroup; def err_incompatible_exception_specs : Error< "target exception specification is not superset of source">; def err_deep_exception_specs_differ : Error< "exception specifications of %select{return|argument}0 types differ">; def warn_missing_exception_specification : Warning< "%0 is missing exception specification '%1'">; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; def err_exception_spec_not_parsed : Error< "exception specification is not available until end of class definition">; // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; def err_access : Error< "%1 is a %select{private|protected}0 member of %3">, AccessControl; def ext_ms_using_declaration_inaccessible : ExtWarn< "using declaration referring to inaccessible member '%0' (which refers " "to accessible member '%1') is a Microsoft compatibility extension">, AccessControl, InGroup; def err_access_ctor : Error< "calling a %select{private|protected}0 constructor of class %2">, AccessControl; def ext_rvalue_to_reference_access_ctor : Extension< "C++98 requires an accessible copy constructor for class %2 when binding " "a reference to a temporary; was %select{private|protected}0">, AccessControl, InGroup; def err_access_base_ctor : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "%select{base class|inherited virtual base class}0 %1 has %select{private|" "protected}3 %select{default |copy |move |*ERROR* |*ERROR* " "|*ERROR*|}2constructor">, AccessControl; def err_access_field_ctor : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "field of type %0 has %select{private|protected}2 " "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">, AccessControl; def err_access_friend_function : Error< "friend function %1 is a %select{private|protected}0 member of %3">, AccessControl; def err_access_dtor : Error< "calling a %select{private|protected}1 destructor of class %0">, AccessControl; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, AccessControl; def err_access_dtor_vbase : Error<"inherited virtual base class %1 has " "%select{private|protected}2 destructor">, AccessControl; def err_access_dtor_temp : Error<"temporary of type %0 has %select{private|protected}1 destructor">, AccessControl; def err_access_dtor_exception : Error<"exception object of type %0 has %select{private|protected}1 " "destructor">, AccessControl; def err_access_dtor_field : Error<"field of type %1 has %select{private|protected}2 destructor">, AccessControl; def err_access_dtor_var : Error<"variable of type %1 has %select{private|protected}2 destructor">, AccessControl; def err_access_dtor_ivar : Error<"instance variable of type %0 has %select{private|protected}1 " "destructor">, AccessControl; def note_previous_access_declaration : Note< "previously declared '%1' here">; def note_access_natural : Note< "%select{|implicitly }1declared %select{private|protected}0 here">; def note_access_constrained_by_path : Note< "constrained by %select{|implicitly }1%select{private|protected}0" " inheritance here">; def note_access_protected_restricted_noobject : Note< "must name member using the type of the current context %0">; def note_access_protected_restricted_ctordtor : Note< "protected %select{constructor|destructor}0 can only be used to " "%select{construct|destroy}0 a base class subobject">; def note_access_protected_restricted_object : Note< "can only access this member on an object of type %0">; def warn_cxx98_compat_sfinae_access_control : Warning< "substitution failure due to access control is incompatible with C++98">, InGroup, DefaultIgnore, NoSFINAE; // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; def err_dependent_nested_name_spec : Error< "nested name specifier for a declaration cannot depend on a template " "parameter">; def err_nested_name_member_ref_lookup_ambiguous : Error< "lookup of %0 in member access expression is ambiguous">; def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn< "lookup of %0 in member access expression is ambiguous; using member of %1">, InGroup; def note_ambig_member_ref_object_type : Note< "lookup in the object type %0 refers here">; def note_ambig_member_ref_scope : Note< "lookup from the current scope refers here">; def err_qualified_member_nonclass : Error< "qualified member access refers to a member in %0">; def err_incomplete_member_access : Error< "member access into incomplete type %0">; def err_incomplete_type : Error< "incomplete type %0 where a complete type is required">; def warn_cxx98_compat_enum_nested_name_spec : Warning< "enumeration type in nested name specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_nested_name_spec_is_not_class : Error< "%0 cannot appear before '::' because it is not a class" "%select{ or namespace|, namespace, or scoped enumeration}1; did you mean ':'?">; // C++ class members def err_storageclass_invalid_for_member : Error< "storage class specified for a member declaration">; def err_mutable_function : Error<"'mutable' cannot be applied to functions">; def err_mutable_reference : Error<"'mutable' cannot be applied to references">; def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">; def err_mutable_nonmember : Error< "'mutable' can only be applied to member variables">; def err_virtual_non_function : Error< "'virtual' can only appear on non-static member functions">; def err_virtual_out_of_class : Error< "'virtual' can only be specified inside the class definition">; def err_virtual_member_function_template : Error< "'virtual' cannot be specified on member function templates">; def err_static_overrides_virtual : Error< "'static' member function %0 overrides a virtual function in a base class">; def err_explicit_non_function : Error< "'explicit' can only appear on non-static member functions">; def err_explicit_out_of_class : Error< "'explicit' can only be specified inside the class definition">; def err_explicit_non_ctor_or_conv_function : Error< "'explicit' can only be applied to a constructor or conversion function">; def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; def err_static_out_of_line : Error< "'static' can only be specified inside the class definition">; def err_storage_class_for_static_member : Error< "static data member definition cannot specify a storage class">; def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">; def err_not_integral_type_bitfield : Error< "bit-field %0 has non-integral type %1">; def err_not_integral_type_anon_bitfield : Error< "anonymous bit-field has non-integral type %0">; def err_member_function_initialization : Error< "initializer on function does not look like a pure-specifier">; def err_non_virtual_pure : Error< "%0 is not virtual and cannot be declared pure">; def ext_pure_function_definition : ExtWarn< "function definition with pure-specifier is a Microsoft extension">, InGroup; def err_implicit_object_parameter_init : Error< "cannot initialize object parameter of type %0 with an expression " "of type %1">; def err_qualified_member_of_unrelated : Error< "%q0 is not a member of class %1">; def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< "call to pure virtual member function %0; overrides of %0 in subclasses are " "not available in the %select{constructor|destructor}1 of %2">; def note_member_declared_at : Note<"member is declared here">; def note_ivar_decl : Note<"instance variable is declared here">; def note_bitfield_decl : Note<"bit-field is declared here">; def note_implicit_param_decl : Note<"%0 is an implicit parameter">; def note_member_synthesized_at : Note< "implicit %select{default constructor|copy constructor|move constructor|copy " "assignment operator|move assignment operator|destructor}0 for %1 first " "required here">; def note_inhctor_synthesized_at : Note< "inheriting constructor for %0 first required here">; def err_missing_default_ctor : Error< "%select{|implicit default |inheriting }0constructor for %1 must explicitly " "initialize the %select{base class|member}2 %3 which does not have a default " "constructor">; def err_illegal_union_or_anon_struct_member : Error< "%select{anonymous struct|union}0 member %1 has a non-trivial " "%select{constructor|copy constructor|move constructor|copy assignment " "operator|move assignment operator|destructor}2">; def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< "%select{anonymous struct|union}0 member %1 with a non-trivial " "%select{constructor|copy constructor|move constructor|copy assignment " "operator|move assignment operator|destructor}2 is incompatible with C++98">, InGroup, DefaultIgnore; def note_nontrivial_virtual_dtor : Note< "destructor for %0 is not trivial because it is virtual">; def note_nontrivial_has_virtual : Note< "because type %0 has a virtual %select{member function|base class}1">; def note_nontrivial_no_def_ctor : Note< "because %select{base class of |field of |}0type %1 has no " "default constructor">; def note_user_declared_ctor : Note< "implicit default constructor suppressed by user-declared constructor">; def note_nontrivial_no_copy : Note< "because no %select{<>|constructor|constructor|assignment operator|" "assignment operator|<>}2 can be used to " "%select{<>|copy|move|copy|move|<>}2 " "%select{base class|field|an object}0 of type %3">; def note_nontrivial_user_provided : Note< "because %select{base class of |field of |}0type %1 has a user-provided " "%select{default constructor|copy constructor|move constructor|" "copy assignment operator|move assignment operator|destructor}2">; def note_nontrivial_in_class_init : Note< "because field %0 has an initializer">; def note_nontrivial_param_type : Note< "because its parameter is %diff{of type $, not $|of the wrong type}2,3">; def note_nontrivial_default_arg : Note<"because it has a default argument">; def note_nontrivial_variadic : Note<"because it is a variadic function">; def note_nontrivial_subobject : Note< "because the function selected to %select{construct|copy|move|copy|move|" "destroy}2 %select{base class|field}0 of type %1 is not trivial">; def note_nontrivial_objc_ownership : Note< "because type %0 has a member with %select{no|no|__strong|__weak|" "__autoreleasing}1 ownership">; def err_static_data_member_not_allowed_in_anon_struct : Error< "static data member %0 not allowed in anonymous struct">; def ext_static_data_member_in_union : ExtWarn< "static data member %0 in union is a C++11 extension">, InGroup; def warn_cxx98_compat_static_data_member_in_union : Warning< "static data member %0 in union is incompatible with C++98">, InGroup, DefaultIgnore; def ext_union_member_of_reference_type : ExtWarn< "union member %0 has reference type %1, which is a Microsoft extension">, InGroup; def err_union_member_of_reference_type : Error< "union member %0 has reference type %1">; def ext_anonymous_struct_union_qualified : Extension< "anonymous %select{struct|union}0 cannot be '%1'">; def err_different_return_type_for_overriding_virtual_function : Error< "virtual function %0 has a different return type " "%diff{($) than the function it overrides (which has return type $)|" "than the function it overrides}1,2">; def note_overridden_virtual_function : Note< "overridden virtual function is here">; def err_conflicting_overriding_cc_attributes : Error< "virtual function %0 has different calling convention attributes " "%diff{($) than the function it overrides (which has calling convention $)|" "than the function it overrides}1,2">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " "%select{private|protected}2 base class of %0">, AccessControl; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " "%0 to base class %1:%2)">; def err_covariant_return_not_derived : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 is not derived from %2)">; def err_covariant_return_incomplete : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 is incomplete)">; def err_covariant_return_type_different_qualifications : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 has different qualifiers than %2)">; def err_covariant_return_type_class_type_more_qualified : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (class type %1 is more qualified than class " "type %2">; // C++ constructors def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; def err_ref_qualifier_constructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; def err_constructor_return_type : Error< "constructor cannot have a return type">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">; def err_constructor_byvalue_arg : Error< "copy constructor must pass its first argument by reference">; def warn_no_constructor_for_refconst : Warning< "%select{struct|interface|union|class|enum}0 %1 does not declare any " "constructor to initialize its non-modifiable members">; def note_refconst_member_not_initialized : Note< "%select{const|reference}0 member %1 will never be initialized">; def ext_ms_explicit_constructor_call : ExtWarn< "explicit constructor calls are a Microsoft extension">, InGroup; // C++ destructors def err_destructor_not_member : Error< "destructor must be a non-static member function">; def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; def err_ref_qualifier_destructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; def err_destructor_redeclared : Error<"destructor cannot be redeclared">; def err_destructor_with_params : Error<"destructor cannot have any parameters">; def err_destructor_variadic : Error<"destructor cannot be variadic">; def err_destructor_typedef_name : Error< "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">; def err_destructor_name : Error< "expected the class name after '~' to name the enclosing class">; def err_destructor_class_name : Error< "expected the class name after '~' to name a destructor">; def err_ident_in_dtor_not_a_type : Error< "identifier %0 in object destruction expression does not name a type">; def err_destructor_expr_type_mismatch : Error< "destructor type %0 in object destruction expression does not match the " "type %1 of the object being destroyed">; def note_destructor_type_here : Note< "type %0 is declared here">; def err_destructor_template : Error< "destructor cannot be declared as a template">; // C++ initialization def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " "base class|a constructor delegation|a vector element|a block element|a " "complex element|a lambda capture|a compound literal initializer|a " "related result|a parameter of CF audited function}0 " "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|" "with an %select{rvalue|lvalue}2 of incompatible type}1,3" "%select{|: different classes%diff{ ($ vs $)|}5,6" "|: different number of parameters (%5 vs %6)" "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" "|: different return type%diff{ ($ vs $)|}5,6" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}6)}4">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot " "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">; def err_lvalue_reference_bind_to_initlist : Error< "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an " "initializer list temporary">; def err_lvalue_reference_bind_to_temporary : Error< "%select{non-const|volatile}0 lvalue reference %diff{to type $ cannot bind " "to a temporary of type $|cannot bind to incompatible temporary}1,2">; def err_lvalue_reference_bind_to_unrelated : Error< "%select{non-const|volatile}0 lvalue reference " "%diff{to type $ cannot bind to a value of unrelated type $|" "cannot bind to a value of unrelated type}1,2">; def err_reference_bind_drops_quals : Error< "binding of reference %diff{to type $ to a value of type $ drops qualifiers|" "drops qualifiers}0,1">; def err_reference_bind_failed : Error< "reference %diff{to type $ could not bind to an %select{rvalue|lvalue}1 of " "type $|could not bind to %select{rvalue|lvalue}1 of incompatible type}0,2">; def err_reference_bind_init_list : Error< "reference to type %0 cannot bind to an initializer list">; def warn_temporary_array_to_pointer_decay : Warning< "pointer is initialized by a temporary array, which will be destroyed at the " "end of the full-expression">, InGroup>; def err_init_list_bad_dest_type : Error< "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " "list">; def err_member_function_call_bad_cvr : Error<"member function %0 not viable: " "'this' argument has type %1, but function is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}2">; def err_reference_bind_to_bitfield : Error< "%select{non-const|volatile}0 reference cannot bind to " "bit-field%select{| %1}2">; def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_reference_without_init : Error< "reference to type %0 requires an initializer">; def note_value_initialization_here : Note< "in value-initialization of type %0 here">; def err_reference_has_multiple_inits : Error< "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< "initialization of non-aggregate type %0 with an initializer list">; def err_init_reference_member_uninitialized : Error< "reference member of type %0 uninitialized">; def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">, InGroup; def warn_base_class_is_uninit : Warning< "base class %0 is uninitialized when used here to access %q1">, InGroup; def warn_reference_field_is_uninit : Warning< "reference %0 is not yet bound to a value when used here">, InGroup; def note_uninit_in_this_constructor : Note< "during field initialization in %select{this|the implicit default}0 " "constructor">; def warn_static_self_reference_in_init : Warning< "static variable %0 is suspiciously used within its own initialization">, InGroup; def warn_uninit_self_reference_in_init : Warning< "variable %0 is uninitialized when used within its own initialization">, InGroup; def warn_uninit_self_reference_in_reference_init : Warning< "reference %0 is not yet bound to a value when used within its own" " initialization">, InGroup; def warn_uninit_var : Warning< "variable %0 is uninitialized when %select{used here|captured by block}1">, InGroup, DefaultIgnore; def warn_sometimes_uninit_var : Warning< "variable %0 is %select{used|captured}1 uninitialized whenever " "%select{'%3' condition is %select{true|false}4|" "'%3' loop %select{is entered|exits because its condition is false}4|" "'%3' loop %select{condition is true|exits because its condition is false}4|" "switch %3 is taken|" "its declaration is reached|" "%3 is called}2">, InGroup, DefaultIgnore; def warn_maybe_uninit_var : Warning< "variable %0 may be uninitialized when " "%select{used here|captured by block}1">, InGroup, DefaultIgnore; def note_uninit_var_def : Note<"variable %0 is declared here">; def note_uninit_var_use : Note< "%select{uninitialized use occurs|variable is captured by block}0 here">; def warn_uninit_byref_blockvar_captured_by_block : Warning< "block pointer variable %0 is uninitialized when captured by block">, InGroup, DefaultIgnore; def note_block_var_fixit_add_initialization : Note< "maybe you meant to use __block %0">; def note_in_omitted_aggregate_initializer : Note< "in implicit initialization of %select{array element %1|field %1}0 " "with omitted initializer">; def note_in_reference_temporary_list_initializer : Note< "in initialization of temporary of type %0 created to " "list-initialize this reference">; def note_var_fixit_add_initialization : Note< "initialize the variable %0 to silence this warning">; def note_uninit_fixit_remove_cond : Note< "remove the %select{'%1' if its condition|condition if it}0 " "is always %select{false|true}2">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; def warn_unsequenced_mod_mod : Warning< "multiple unsequenced modifications to %0">, InGroup; def warn_unsequenced_mod_use : Warning< "unsequenced modification and access to %0">, InGroup; def err_temp_copy_no_viable : Error< "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1">; def ext_rvalue_to_reference_temp_copy_no_viable : Extension< "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1; C++98 requires a copy " "constructor when binding a reference to a temporary">, InGroup; def err_temp_copy_ambiguous : Error< "ambiguous constructor call when %select{copying variable|copying " "parameter|returning object|throwing object|copying member subobject|copying " "array element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1">; def err_temp_copy_deleted : Error< "%select{copying variable|copying parameter|returning object|throwing " "object|copying member subobject|copying array element|allocating object|" "copying temporary|initializing base subobject|initializing vector element|" "capturing value}0 of type %1 invokes deleted constructor">; def err_temp_copy_incomplete : Error< "copying a temporary object of incomplete type %0">; def warn_cxx98_compat_temp_copy : Warning< "%select{copying variable|copying parameter|returning object|throwing " "object|copying member subobject|copying array element|allocating object|" "copying temporary|initializing base subobject|initializing vector element}1 " "of type %2 when binding a reference to a temporary would %select{invoke " "an inaccessible constructor|find no viable constructor|find ambiguous " "constructors|invoke a deleted constructor}0 in C++98">, InGroup, DefaultIgnore; def err_selected_explicit_constructor : Error< "chosen constructor is explicit in copy-initialization">; def note_constructor_declared_here : Note< "constructor declared here">; // C++11 decltype def err_decltype_in_declarator : Error< "'decltype' cannot be used to name a declaration">; // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_auto_variable_cannot_appear_in_own_initializer : Error< "variable %0 declared with 'auto' type cannot appear in its own initializer">; def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype" "|in non-static struct member" "|in non-static union member|in non-static class member|in interface member" "|in exception declaration|in template parameter|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter}1">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; def err_auto_new_requires_ctor_arg : Error< "new expression for type %0 requires a constructor argument">; def err_auto_new_list_init : Error< "new expression for type %0 cannot use list-initialization">; def err_auto_var_init_no_expression : Error< "initializer for variable %0 with type %1 is empty">; def err_auto_var_init_multiple_expressions : Error< "initializer for variable %0 with type %1 contains multiple expressions">; def err_auto_var_init_paren_braces : Error< "cannot deduce type for variable %0 with type %1 from " "parenthesized initializer list">; +def warn_auto_var_direct_list_init : Warning< + "direct list initialization of a variable with a deduced type will change " + "meaning in a future version of Clang; insert an '=' to avoid a change in " + "behavior">, InGroup; def err_auto_new_ctor_multiple_expressions : Error< "new expression for type %0 contains multiple constructor arguments">; def err_auto_missing_trailing_return : Error< "'auto' return without trailing return type; deduced return types are a " "C++14 extension">; def err_deduced_return_type : Error< "deduced return types are a C++14 extension">; def err_trailing_return_without_auto : Error< "function with trailing return type must specify return type 'auto', not %0">; def err_trailing_return_in_parens : Error< "trailing return type may not be nested within parentheses">; def err_auto_var_deduction_failure : Error< "variable %0 with type %1 has incompatible initializer of type %2">; def err_auto_var_deduction_failure_from_init_list : Error< "cannot deduce actual type for variable %0 with type %1 from initializer list">; def err_auto_new_deduction_failure : Error< "new expression for type %0 has incompatible constructor argument of type %1">; def err_auto_different_deductions : Error< "'%select{auto|decltype(auto)}0' deduced as %1 in declaration of %2 and " "deduced as %3 in declaration of %4">; def err_implied_std_initializer_list_not_found : Error< "cannot deduce type of initializer list because std::initializer_list was " "not found; include ">; def err_malformed_std_initializer_list : Error< "std::initializer_list must be a class template with a single type parameter">; def warn_dangling_std_initializer_list : Warning< "array backing the initializer list will be destroyed at the end of " "%select{the full-expression|the constructor}0">, InGroup>; // C++1y decltype(auto) type def err_decltype_auto_cannot_be_combined : Error< "'decltype(auto)' cannot be combined with other type specifiers">; def err_decltype_auto_function_declarator_not_declaration : Error< "'decltype(auto)' can only be used as a return type " "in a function declaration">; def err_decltype_auto_compound_type : Error< "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; // C++1y deduced return types def err_auto_fn_deduction_failure : Error< "cannot deduce return type %0 from returned value of type %1">; def err_auto_fn_different_deductions : Error< "'%select{auto|decltype(auto)}0' in return type deduced as %1 here but " "deduced as %2 in earlier return statement">; def err_auto_fn_used_before_defined : Error< "function %0 with deduced return type cannot be used before it is defined">; def err_auto_fn_no_return_but_not_auto : Error< "cannot deduce return type %0 for function with no return statements">; def err_auto_fn_return_void_but_not_auto : Error< "cannot deduce return type %0 from omitted return expression">; def err_auto_fn_return_init_list : Error< "cannot deduce return type from initializer list">; def err_auto_fn_virtual : Error< "function with deduced return type cannot be virtual">; // C++11 override control def override_keyword_only_allowed_on_virtual_member_functions : Error< "only virtual member functions can be marked '%0'">; def override_keyword_hides_virtual_member_function : Error< "non-virtual member function marked '%0' hides virtual member " "%select{function|functions}1">; def err_function_marked_override_not_overriding : Error< "%0 marked 'override' but does not override any member functions">; def warn_function_marked_not_override_overriding : Warning < "%0 overrides a member function but is not marked 'override'">, InGroup; def err_class_marked_final_used_as_base : Error< "base %0 is marked '%select{final|sealed}1'">; def warn_abstract_final_class : Warning< "abstract class is marked '%select{final|sealed}0'">, InGroup; // C++11 attributes def err_repeat_attribute : Error<"%0 attribute cannot be repeated">; // C++11 final def err_final_function_overridden : Error< "declaration of %0 overrides a '%select{final|sealed}1' function">; // C++11 scoped enumerations def err_enum_invalid_underlying : Error< "non-integral type %0 is an invalid underlying type">; def err_enumerator_too_large : Error< "enumerator value is not representable in the underlying type %0">; def ext_enumerator_too_large : ExtWarn< "enumerator value is not representable in the underlying type %0">, InGroup; def err_enumerator_wrapped : Error< "enumerator value %0 is not representable in the underlying type %1">; def err_enum_redeclare_type_mismatch : Error< "enumeration redeclared with different underlying type %0 (was %1)">; def err_enum_redeclare_fixed_mismatch : Error< "enumeration previously declared with %select{non|}0fixed underlying type">; def err_enum_redeclare_scoped_mismatch : Error< "enumeration previously declared as %select{un|}0scoped">; def err_enum_class_reference : Error< "reference to %select{|scoped }0enumeration must use 'enum' " "not 'enum class'">; def err_only_enums_have_underlying_types : Error< "only enumeration types have underlying types">; def err_underlying_type_of_incomplete_enum : Error< "cannot determine underlying type of incomplete enumeration type %0">; // C++11 delegating constructors def err_delegating_ctor : Error< "delegating constructors are permitted only in C++11">; def warn_cxx98_compat_delegating_ctor : Warning< "delegating constructors are incompatible with C++98">, InGroup, DefaultIgnore; def err_delegating_initializer_alone : Error< "an initializer for a delegating constructor must appear alone">; def warn_delegating_ctor_cycle : Warning< "constructor for %0 creates a delegation cycle">, DefaultError, InGroup; def note_it_delegates_to : Note<"it delegates to">; def note_which_delegates_to : Note<"which delegates to">; // C++11 range-based for loop def err_for_range_decl_must_be_var : Error< "for range declaration must declare a variable">; def err_for_range_storage_class : Error< "loop variable %0 may not be declared %select{'extern'|'static'|" "'__private_extern__'|'auto'|'register'|'constexpr'}1">; def err_type_defined_in_for_range : Error< "types may not be defined in a for range declaration">; def err_for_range_deduction_failure : Error< "cannot use type %0 as a range">; def err_for_range_incomplete_type : Error< "cannot use incomplete type %0 as a range">; def err_for_range_iter_deduction_failure : Error< "cannot use type %0 as an iterator">; def err_for_range_member_begin_end_mismatch : Error< "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">; def err_for_range_begin_end_types_differ : Error< "'begin' and 'end' must return the same type (got %0 and %1)">; def note_in_for_range: Note< "when looking up '%select{begin|end}0' function for range expression " "of type %1">; def err_for_range_invalid: Error< "invalid range expression of type %0; no viable '%select{begin|end}1' " "function available">; def err_range_on_array_parameter : Error< "cannot build range expression with array function parameter %0 since " "parameter with array type %1 is treated as pointer type %2">; def err_for_range_dereference : Error< "invalid range expression of type %0; did you mean to dereference it " "with '*'?">; def note_for_range_invalid_iterator : Note < "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">; def note_for_range_begin_end : Note< "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">; // C++11 constexpr def warn_cxx98_compat_constexpr : Warning< "'constexpr' specifier is incompatible with C++98">, InGroup, DefaultIgnore; // FIXME: Maybe this should also go in -Wc++14-compat? def warn_cxx14_compat_constexpr_not_const : Warning< "'constexpr' non-static member function will not be implicitly 'const' " "in C++14; add 'const' to avoid a change in behavior">, InGroup>; def err_invalid_constexpr : Error< "%select{function parameter|typedef|non-static data member}0 " "cannot be constexpr">; def err_invalid_constexpr_member : Error<"non-static data member cannot be " "constexpr%select{; did you intend to make it %select{const|static}0?|}1">; def err_constexpr_tag : Error< "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">; def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; def err_constexpr_no_declarators : Error< "constexpr can only be used in variable and function declarations">; def err_invalid_constexpr_var_decl : Error< "constexpr variable declaration must be a definition">; def err_constexpr_static_mem_var_requires_init : Error< "declaration of constexpr static data member %0 requires an initializer">; def err_constexpr_var_non_literal : Error< "constexpr variable cannot have non-literal type %0">; def err_constexpr_var_requires_const_init : Error< "constexpr variable %0 must be initialized by a constant expression">; def err_constexpr_redecl_mismatch : Error< "%select{non-constexpr declaration of %0 follows constexpr declaration" "|constexpr declaration of %0 follows non-constexpr declaration}1">; def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; def err_constexpr_virtual_base : Error< "constexpr %select{member function|constructor}0 not allowed in " "%select{struct|interface|class}1 with virtual base " "%plural{1:class|:classes}2">; def note_non_literal_incomplete : Note< "incomplete type %0 is not a literal type">; def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 " "with virtual base %plural{1:class|:classes}1 is not a literal type">; def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; def err_constexpr_non_literal_return : Error< "constexpr function's return type %0 is not a literal type">; def err_constexpr_non_literal_param : Error< "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " "not a literal type">; def err_constexpr_body_invalid_stmt : Error< "statement not allowed in constexpr %select{function|constructor}0">; def ext_constexpr_body_invalid_stmt : ExtWarn< "use of this statement in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning< "use of this statement in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def ext_constexpr_type_definition : ExtWarn< "type definition in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_type_definition : Warning< "type definition in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_constexpr_vla : Error< "variably-modified type %0 cannot be used in a constexpr " "%select{function|constructor}1">; def ext_constexpr_local_var : ExtWarn< "variable declaration in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_local_var : Warning< "variable declaration in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_constexpr_local_var_static : Error< "%select{static|thread_local}1 variable not permitted in a constexpr " "%select{function|constructor}0">; def err_constexpr_local_var_non_literal_type : Error< "variable of non-literal type %1 cannot be defined in a constexpr " "%select{function|constructor}0">; def err_constexpr_local_var_no_init : Error< "variables defined in a constexpr %select{function|constructor}0 must be " "initialized">; def ext_constexpr_function_never_constant_expr : ExtWarn< "constexpr %select{function|constructor}0 never produces a " "constant expression">, InGroup>, DefaultError; def err_enable_if_never_constant_expr : Error< "'enable_if' attribute expression never produces a constant expression">; def err_constexpr_body_no_return : Error< "no return statement in constexpr function">; def err_constexpr_return_missing_expr : Error< "non-void constexpr function %0 should return a value">; def warn_cxx11_compat_constexpr_body_no_return : Warning< "constexpr function with no return statements is incompatible with C++ " "standards before C++14">, InGroup, DefaultIgnore; def ext_constexpr_body_multiple_return : ExtWarn< "multiple return statements in constexpr function is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_body_multiple_return : Warning< "multiple return statements in constexpr function " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def note_constexpr_body_previous_return : Note< "previous return statement is here">; def err_constexpr_function_try_block : Error< "function try block not allowed in constexpr %select{function|constructor}0">; def err_constexpr_union_ctor_no_init : Error< "constexpr union constructor does not initialize any member">; def err_constexpr_ctor_missing_init : Error< "constexpr constructor must initialize all members">; def note_constexpr_ctor_missing_init : Note< "member not initialized by constructor">; def note_non_literal_no_constexpr_ctors : Note< "%0 is not literal because it is not an aggregate and has no constexpr " "constructors other than copy or move constructors">; def note_non_literal_base_class : Note< "%0 is not literal because it has base class %1 of non-literal type">; def note_non_literal_field : Note< "%0 is not literal because it has data member %1 of " "%select{non-literal|volatile}3 type %2">; def note_non_literal_user_provided_dtor : Note< "%0 is not literal because it has a user-provided destructor">; def note_non_literal_nontrivial_dtor : Note< "%0 is not literal because it has a non-trivial destructor">; def warn_private_extern : Warning< "use of __private_extern__ on a declaration may not produce external symbol " "private to the linkage unit and is deprecated">, InGroup; def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< "'%0' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< "Objective-C declarations may only appear in global scope">; def warn_auto_var_is_id : Warning< "'auto' deduced as 'id' in declaration of %0">, InGroup>; // Attributes def err_nsobject_attribute : Error< "'NSObject' attribute is for pointer types only">; def err_attributes_are_not_compatible : Error< "%0 and %1 attributes are not compatible">; def err_attribute_wrong_number_arguments : Error< "%0 attribute %plural{0:takes no arguments|1:takes one argument|" ":requires exactly %1 arguments}1">; def err_attribute_too_many_arguments : Error< "%0 attribute takes no more than %1 argument%s1">; def err_attribute_too_few_arguments : Error< "%0 attribute takes at least %1 argument%s1">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; def err_attribute_unsupported : Error< "%0 attribute is not supported for this target">; // The err_*_attribute_argument_not_int are seperate because they're used by // VerifyIntegerConstantExpression. def err_aligned_attribute_argument_not_int : Error< "'aligned' attribute requires integer constant">; def err_align_value_attribute_argument_not_int : Error< "'align_value' attribute requires integer constant">; def err_alignas_attribute_wrong_decl_type : Error< "%0 attribute cannot be applied to a %select{function parameter|" "variable with 'register' storage class|'catch' variable|bit-field}1">; def err_alignas_missing_on_definition : Error< "%0 must be specified on definition if it is specified on any declaration">; def note_alignas_on_declaration : Note<"declared with %0 attribute here">; def err_alignas_mismatch : Error< "redeclaration has different alignment requirement (%1 vs %0)">; def err_alignas_underaligned : Error< "requested alignment is less than minimum alignment of %1 for type %0">; def err_attribute_argument_n_type : Error< "%0 attribute requires parameter %1 to be %select{int or bool|an integer " "constant|a string|an identifier}2">; def err_attribute_argument_type : Error< "%0 attribute requires %select{int or bool|an integer " "constant|a string|an identifier}1">; def err_attribute_argument_outof_range : Error< "init_priority attribute requires integer constant between " "101 and 65535 inclusive">; def err_init_priority_object_attr : Error< "can only use 'init_priority' attribute on file-scope definitions " "of objects of class type">; def err_attribute_argument_vec_type_hint : Error< "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">; def err_attribute_argument_out_of_bounds : Error< "%0 attribute parameter %1 is out of bounds">; def err_attribute_uuid_malformed_guid : Error< "uuid attribute contains a malformed GUID">; def warn_attribute_pointers_only : Warning< "%0 attribute only applies to pointer arguments">, InGroup; def err_attribute_pointers_only : Error; def warn_attribute_return_pointers_only : Warning< "%0 attribute only applies to return values that are pointers">, InGroup; def warn_attribute_return_pointers_refs_only : Warning< "%0 attribute only applies to return values that are pointers or references">, InGroup; def warn_attribute_pointer_or_reference_only : Warning< "%0 attribute only applies to a pointer or reference (%1 is invalid)">, InGroup; def err_attribute_no_member_pointers : Error< "%0 attribute cannot be used with pointers to members">; def err_attribute_invalid_implicit_this_argument : Error< "%0 attribute is invalid for the implicit this argument">; def err_ownership_type : Error< "%0 attribute only applies to %select{pointer|integer}1 arguments">; def err_ownership_returns_index_mismatch : Error< "'ownership_returns' attribute index does not match; here it is %0">; def note_ownership_returns_index_mismatch : Note< "declared with index %0 here">; def err_format_strftime_third_parameter : Error< "strftime format attribute requires 3rd parameter to be 0">; def err_format_attribute_requires_variadic : Error< "format attribute requires variadic function">; def err_format_attribute_not : Error<"format argument not %0">; def err_format_attribute_result_not : Error<"function does not return %0">; def err_format_attribute_implicit_this_format_string : Error< "format attribute cannot specify the implicit this argument as the format " "string">; def err_init_method_bad_return_type : Error< "init methods must return an object pointer type, not %0">; def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; def err_attribute_size_too_large : Error<"vector size too large">; def err_typecheck_vector_not_convertable : Error< "can't convert between vector values of different size (%0 and %1)">; def err_typecheck_vector_not_convertable_non_scalar : Error< "can't convert between vector and non-scalar values (%0 and %1)">; def err_ext_vector_component_exceeds_length : Error< "vector component access exceeds type %0">; def err_ext_vector_component_name_illegal : Error< "illegal vector component name '%0'">; def err_attribute_address_space_negative : Error< "address space is negative">; def err_attribute_address_space_too_high : Error< "address space is larger than the maximum supported (%0)">; def err_attribute_address_multiple_qualifiers : Error< "multiple address spaces specified for type">; def err_attribute_address_function_type : Error< "function type may not be qualified with an address space">; def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; def err_arg_with_address_space : Error< "parameter may not be qualified with an address space">; def err_field_with_address_space : Error< "field may not be qualified with an address space">; def err_attr_objc_ownership_redundant : Error< "the type %0 is already explicitly ownership-qualified">; def err_undeclared_nsnumber : Error< "NSNumber must be available to use Objective-C literals">; def err_invalid_nsnumber_type : Error< "%0 is not a valid literal type for NSNumber">; def err_undeclared_nsstring : Error< "cannot box a string value because NSString has not been declared">; def err_objc_illegal_boxed_expression_type : Error< "illegal type %0 used in a boxed expression">; def err_objc_incomplete_boxed_expression_type : Error< "incomplete type %0 used in a boxed expression">; def err_undeclared_nsarray : Error< "NSArray must be available to use Objective-C array literals">; def err_undeclared_nsdictionary : Error< "NSDictionary must be available to use Objective-C dictionary " "literals">; def err_undeclared_boxing_method : Error< "declaration of %0 is missing in %1 class">; def err_objc_literal_method_sig : Error< "literal construction method %0 has incompatible signature">; def note_objc_literal_method_param : Note< "%select{first|second|third}0 parameter has unexpected type %1 " "(should be %2)">; def note_objc_literal_method_return : Note< "method returns unexpected type %0 (should be an object type)">; def err_invalid_collection_element : Error< "collection element of type %0 is not an Objective-C object">; def err_box_literal_collection : Error< "%select{string|character|boolean|numeric}0 literal must be prefixed by '@' " "in a collection">; def warn_objc_literal_comparison : Warning< "direct comparison of %select{an array literal|a dictionary literal|" "a numeric literal|a boxed expression|}0 has undefined behavior">, InGroup; def err_missing_atsign_prefix : Error< "string literal must be prefixed by '@' ">; def warn_objc_string_literal_comparison : Warning< "direct comparison of a string literal has undefined behavior">, InGroup; def warn_concatenated_nsarray_literal : Warning< "concatenated NSString literal for an NSArray expression - " "possibly missing a comma">, InGroup; def note_objc_literal_comparison_isequal : Note< "use 'isEqual:' instead">; def err_attribute_argument_is_zero : Error< "%0 attribute must be greater than 0">; def err_property_function_in_objc_container : Error< "use of Objective-C property in function nested in Objective-C " "container not supported, move function outside its container">; let CategoryName = "Cocoa API Issue" in { def warn_objc_redundant_literal_use : Warning< "using %0 with a literal is redundant">, InGroup; } def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">; def err_only_annotate_after_access_spec : Error< "access specifier can only have annotation attributes">; def err_attribute_section_invalid_for_target : Error< "argument to 'section' attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup
; def err_anonymous_property: Error< "anonymous property is not supported">; def err_property_is_variably_modified : Error< "property %0 has a variably modified type">; def err_no_accessor_for_property : Error< "no %select{getter|setter}0 defined for property %1">; def error_cannot_find_suitable_accessor : Error< "cannot find suitable %select{getter|setter}0 for property %1">; def err_alignment_not_power_of_two : Error< "requested alignment is not a power of 2">; def err_attribute_aligned_too_great : Error< "requested alignment must be %0 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "%q0 redeclared without %1 attribute: previous %1 ignored">, InGroup>; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup; def warn_attribute_ignored_on_inline : Warning<"%0 attribute ignored on inline function">, InGroup; def warn_attribute_after_definition_ignored : Warning< "attribute %0 after definition is ignored">, InGroup; def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup; def warn_cxx11_gnu_attribute_on_type : Warning< "attribute %0 ignored, because it cannot be applied to a type">, InGroup; def warn_unhandled_ms_attribute_ignored : Warning< "__declspec attribute %0 is not supported">, InGroup; def err_attribute_invalid_on_stmt : Error< "%0 attribute cannot be applied to a statement">; def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after " "\"%select{class|struct|union|interface|enum}1\" to apply attribute to " "type declaration">, InGroup; def warn_attribute_precede_definition : Warning< "attribute declaration must precede definition">, InGroup; def warn_attribute_void_function_method : Warning< "attribute %0 cannot be applied to " "%select{functions|Objective-C method}1 without return value">, InGroup; def warn_attribute_weak_on_field : Warning< "__weak attribute cannot be specified on a field declaration">, InGroup; def warn_gc_attribute_weak_on_local : Warning< "Objective-C GC does not allow weak variables on the stack">, InGroup; def warn_nsobject_attribute : Warning< "'NSObject' attribute may be put on a typedef only; attribute is ignored">, InGroup; def warn_attribute_weak_on_local : Warning< "__weak attribute cannot be specified on an automatic variable when ARC " "is not enabled">, InGroup; def warn_weak_identifier_undeclared : Warning< "weak identifier %0 never declared">; def err_attribute_weak_static : Error< "weak declaration cannot have internal linkage">; def err_attribute_selectany_non_extern_data : Error< "'selectany' can only be applied to data items with external linkage">; def err_declspec_thread_on_thread_variable : Error< "'__declspec(thread)' applied to variable that already has a " "thread-local storage specifier">; def err_attribute_dll_not_extern : Error< "%q0 must have external linkage when declared %q1">; def err_attribute_dll_thread_local : Error< "%q0 cannot be thread local when declared %q1">; def warn_attribute_invalid_on_definition : Warning< "'%0' attribute cannot be specified on a definition">, InGroup; def err_attribute_dll_redeclaration : Error< "redeclaration of %q0 cannot add %q1 attribute">; def warn_attribute_dll_redeclaration : Warning< "redeclaration of %q0 should not add %q1 attribute">, InGroup>; def err_attribute_dllimport_function_definition : Error< "dllimport cannot be applied to non-inline function definition">; def err_attribute_dll_deleted : Error< "attribute %q0 cannot be applied to a deleted function">; def err_attribute_dllimport_data_definition : Error< "definition of dllimport data">; def err_attribute_dllimport_static_field_definition : Error< "definition of dllimport static field not allowed">; def warn_attribute_dllimport_static_field_definition : Warning< "definition of dllimport static field">, InGroup>; def warn_invalid_initializer_from_system_header : Warning< "invalid constructor form class in system header, should not be explicit">, InGroup>; def note_used_in_initialization_here : Note<"used in initialization here">; def err_attribute_dll_member_of_dll_class : Error< "attribute %q0 cannot be applied to member of %q1 class">; def warn_attribute_dll_instantiated_base_class : Warning< "propagating dll attribute to %select{already instantiated|explicitly specialized}0 " "base class template " "%select{without dll attribute|with different dll attribute}1 is not supported">, InGroup>, DefaultIgnore; def err_attribute_weakref_not_static : Error< "weakref declaration must have internal linkage">; def err_attribute_weakref_not_global_context : Error< "weakref declaration of %0 must be in a global context">; def err_attribute_weakref_without_alias : Error< "weakref declaration of %0 must also have an alias attribute">; def err_alias_not_supported_on_darwin : Error < "only weak aliases are supported on darwin">; def err_alias_to_undefined : Error< "alias must point to a defined variable or function">; def warn_alias_to_weak_alias : Warning< "alias will always resolve to %0 even if weak definition of alias %1 is overridden">, InGroup; def warn_alias_with_section : Warning< "alias will not be in section '%0' but in the same section as the aliasee">, InGroup; def err_duplicate_mangled_name : Error< "definition with same mangled name as another definition">; def err_cyclic_alias : Error< "alias definition is part of a cycle">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{functions|unions|" "variables and functions|functions and methods|parameters|" "functions, methods and blocks|functions, methods, and classes|" "functions, methods, and parameters|classes|variables|methods|" "variables, functions and labels|fields and global variables|structs|" "variables and typedefs|thread-local variables|" "variables and fields|variables, data members and tag types|" "types and namespaces|Objective-C interfaces|methods and properties|" "struct or union|struct, union or class|types|" "Objective-C instance methods|init methods of interface or class extension declarations|" "variables, functions and classes|Objective-C protocols|" "functions and global variables|structs or typedefs|" "interface or protocol declarations|kernel functions}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, InGroup; def warn_incomplete_encoded_type : Warning< "encoding of %0 type is incomplete because %1 component has unknown encoding">, InGroup>; def warn_attribute_requires_functions_or_static_globals : Warning< "%0 only applies to variables with static storage duration and functions">, InGroup; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">, InGroup; def err_attribute_vecreturn_only_vector_member : Error< "the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">; def err_attribute_vecreturn_only_pod_record : Error< "the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">; def err_cconv_change : Error< "function declared '%0' here was previously declared " "%select{'%2'|without calling convention}1">; def warn_cconv_ignored : Warning< "calling convention %0 ignored for this target">, InGroup; def err_cconv_knr : Error< "function with no prototype cannot use the %0 calling convention">; def warn_cconv_knr : Warning< err_cconv_knr.Text>, InGroup>; def err_cconv_varargs : Error< "variadic function cannot use %0 calling convention">; def warn_cconv_varargs : Warning< "%0 calling convention ignored on variadic function">, InGroup; def err_regparm_mismatch : Error<"function declared with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; def err_returns_retained_mismatch : Error< "function declared with the ns_returns_retained attribute " "was previously declared without the ns_returns_retained attribute">; def err_objc_precise_lifetime_bad_type : Error< "objc_precise_lifetime only applies to retainable types; type here is %0">; def warn_objc_precise_lifetime_meaningless : Error< "objc_precise_lifetime is not meaningful for " "%select{__unsafe_unretained|__autoreleasing}0 objects">; def err_invalid_pcs : Error<"invalid PCS type">; def warn_attribute_not_on_decl : Warning< "%0 attribute ignored when parsing type">, InGroup; def err_base_specifier_attribute : Error< "%0 attribute cannot be applied to a base specifier">; // Availability attribute def warn_availability_unknown_platform : Warning< "unknown platform %0 in availability macro">, InGroup; def warn_availability_version_ordering : Warning< "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " "attribute ignored">, InGroup; def warn_mismatched_availability: Warning< "availability does not match previous declaration">, InGroup; def warn_mismatched_availability_override : Warning< "overriding method %select{introduced after|" "deprecated before|obsoleted before}0 overridden method on %1 (%2 vs. %3)">, InGroup; def warn_mismatched_availability_override_unavail : Warning< "overriding method cannot be unavailable on %0 when its overridden method is " "available">, InGroup; def note_overridden_method : Note< "overridden method is here">; // Thread Safety Attributes def warn_invalid_capability_name : Warning< "invalid capability name '%0'; capability name must be 'mutex' or 'role'">, InGroup, DefaultIgnore; def warn_thread_attribute_ignored : Warning< "ignoring %0 attribute because its argument is invalid">, InGroup, DefaultIgnore; def warn_thread_attribute_argument_not_lockable : Warning< "%0 attribute requires arguments whose type is annotated " "with 'capability' attribute; type here is %1">, InGroup, DefaultIgnore; def warn_thread_attribute_decl_not_lockable : Warning< "%0 attribute can only be applied in a context annotated " "with 'capability(\"mutex\")' attribute">, InGroup, DefaultIgnore; def warn_thread_attribute_decl_not_pointer : Warning< "%0 only applies to pointer types; type here is %1">, InGroup, DefaultIgnore; def err_attribute_argument_out_of_range : Error< "%0 attribute parameter %1 is out of bounds: " "%plural{0:no parameters to index into|" "1:can only be 1, since there is one parameter|" ":must be between 1 and %2}2">; // Thread Safety Analysis def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">, InGroup, DefaultIgnore; def warn_unlock_kind_mismatch : Warning< "releasing %0 '%1' using %select{shared|exclusive}2 access, expected " "%select{shared|exclusive}3 access">, InGroup, DefaultIgnore; def warn_double_lock : Warning<"acquiring %0 '%1' that is already held">, InGroup, DefaultIgnore; def warn_no_unlock : Warning< "%0 '%1' is still held at the end of function">, InGroup, DefaultIgnore; def warn_expecting_locked : Warning< "expecting %0 '%1' to be held at the end of function">, InGroup, DefaultIgnore; // FIXME: improve the error message about locks not in scope def warn_lock_some_predecessors : Warning< "%0 '%1' is not held on every path through here">, InGroup, DefaultIgnore; def warn_expecting_lock_held_on_loop : Warning< "expecting %0 '%1' to be held at start of each loop">, InGroup, DefaultIgnore; def note_locked_here : Note<"%0 acquired here">; def warn_lock_exclusive_and_shared : Warning< "%0 '%1' is acquired exclusively and shared in the same scope">, InGroup, DefaultIgnore; def note_lock_exclusive_and_shared : Note< "the other acquisition of %0 '%1' is here">; def warn_variable_requires_any_lock : Warning< "%select{reading|writing}1 variable '%0' requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup, DefaultIgnore; def warn_var_deref_requires_any_lock : Warning< "%select{reading|writing}1 the value pointed to by '%0' requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup, DefaultIgnore; def warn_fun_excludes_mutex : Warning< "cannot call function '%1' while %0 '%2' is held">, InGroup, DefaultIgnore; def warn_cannot_resolve_lock : Warning< "cannot resolve lock expression">, InGroup, DefaultIgnore; // Thread safety warnings negative capabilities def warn_acquire_requires_negative_cap : Warning< "acquiring %0 '%1' requires negative capability '%2'">, InGroup, DefaultIgnore; // Thread safety warnings on pass by reference def warn_guarded_pass_by_reference : Warning< "passing variable '%1' by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_pt_guarded_pass_by_reference : Warning< "passing the value that '%1' points to by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; // Imprecise thread safety warnings def warn_variable_requires_lock : Warning< "%select{reading|writing}3 variable '%1' requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_var_deref_requires_lock : Warning< "%select{reading|writing}3 the value pointed to by '%1' requires " "holding %0 %select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_fun_requires_lock : Warning< "calling function '%1' requires holding %0 %select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; // Precise thread safety warnings def warn_variable_requires_lock_precise : Warning, InGroup, DefaultIgnore; def warn_var_deref_requires_lock_precise : Warning, InGroup, DefaultIgnore; def warn_fun_requires_lock_precise : Warning, InGroup, DefaultIgnore; def note_found_mutex_near_match : Note<"found near match '%0'">; // Verbose thread safety warnings def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, InGroup, DefaultIgnore; def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">; def note_guarded_by_declared_here : Note<"Guarded_by declared here.">; // Dummy warning that will trigger "beta" warnings from the analysis if enabled. def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, InGroup, DefaultIgnore; // Consumed warnings def warn_use_in_invalid_state : Warning< "invalid invocation of method '%0' on object '%1' while it is in the '%2' " "state">, InGroup, DefaultIgnore; def warn_use_of_temp_in_invalid_state : Warning< "invalid invocation of method '%0' on a temporary object while it is in the " "'%1' state">, InGroup, DefaultIgnore; def warn_attr_on_unconsumable_class : Warning< "consumed analysis attribute is attached to member of class '%0' which isn't " "marked as consumable">, InGroup, DefaultIgnore; def warn_return_typestate_for_unconsumable_type : Warning< "return state set for an unconsumable type '%0'">, InGroup, DefaultIgnore; def warn_return_typestate_mismatch : Warning< "return value not in expected state; expected '%0', observed '%1'">, InGroup, DefaultIgnore; def warn_loop_state_mismatch : Warning< "state of variable '%0' must match at the entry and exit of loop">, InGroup, DefaultIgnore; def warn_param_return_typestate_mismatch : Warning< "parameter '%0' not in expected state when the function returns: expected " "'%1', observed '%2'">, InGroup, DefaultIgnore; def warn_param_typestate_mismatch : Warning< "argument not in expected state; expected '%0', observed '%1'">, InGroup, DefaultIgnore; def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_complex_scalar : Warning< "implicit conversion discards imaginary component: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_float_integer : Warning< "implicit conversion turns floating-point number into integer: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_sign : Warning< "implicit conversion changes signedness: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_sign_conditional : Warning< "operand of ? changes signedness: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_precision : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_64_32 : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_precision_constant : Warning< "implicit conversion from %2 to %3 changes value from %0 to %1">, InGroup; def warn_impcast_bitfield_precision_constant : Warning< "implicit truncation from %2 to bitfield changes value from %0 to %1">, InGroup; def warn_impcast_literal_float_to_integer : Warning< "implicit conversion from %0 to %1 changes value from %2 to %3">, InGroup; def warn_impcast_string_literal_to_bool : Warning< "implicit conversion turns string literal into bool: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_different_enum_types : Warning< "implicit conversion from enumeration type %0 to different enumeration type " "%1">, InGroup; def warn_impcast_bool_to_null_pointer : Warning< "initialization of pointer of type %0 to null from a constant boolean " "expression">, InGroup; def warn_non_literal_null_pointer : Warning< "expression which evaluates to zero treated as a null pointer constant of " "type %0">, InGroup; def warn_impcast_null_pointer_to_integer : Warning< "implicit conversion of %select{NULL|nullptr}0 constant to %1">, InGroup; def warn_impcast_floating_point_to_bool : Warning< "implicit conversion turns floating-point number into bool: %0 to %1">, InGroup; def warn_impcast_pointer_to_bool : Warning< "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup; def warn_cast_nonnull_to_bool : Warning< "nonnull parameter '%0' will evaluate to " "'true' on first encounter">, InGroup; def warn_this_bool_conversion : Warning< "'this' pointer cannot be null in well-defined C++ code; pointer may be " "assumed to always convert to true">, InGroup; def warn_address_of_reference_bool_conversion : Warning< "reference cannot be bound to dereferenced null pointer in well-defined C++ " "code; pointer may be assumed to always convert to true">, InGroup; def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup; def warn_nonnull_parameter_compare : Warning< "comparison of nonnull parameter '%0' %select{not |}1" "equal to a null pointer is %select{true|false}1 on first encounter">, InGroup; def warn_this_null_compare : Warning< "'this' pointer cannot be null in well-defined C++ code; comparison may be " "assumed to always evaluate to %select{true|false}0">, InGroup; def warn_address_of_reference_null_compare : Warning< "reference cannot be bound to dereferenced null pointer in well-defined C++ " "code; comparison may be assumed to always evaluate to " "%select{true|false}0">, InGroup; def note_reference_is_return_value : Note<"%0 returns a reference">; def note_function_warning_silence : Note< "prefix with the address-of operator to silence this warning">; def note_function_to_function_call : Note< "suffix with parentheses to turn this into a function call">; def warn_impcast_objective_c_literal_to_bool : Warning< "implicit boolean conversion of Objective-C object literal always " "evaluates to true">, InGroup; def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, InGroup, DefaultIgnore; def warn_old_style_cast : Warning< "use of old-style cast">, InGroup, DefaultIgnore; // Separate between casts to void* and non-void* pointers. // Some APIs use (abuse) void* for something like a user context, // and often that value is an integer even if it isn't a pointer itself. // Having a separate warning flag allows users to control the warning // for their workflow. def warn_int_to_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; def warn_int_to_void_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; def warn_attribute_ignored_for_field_of_type : Warning< "%0 attribute ignored for field of type %1">, InGroup; def warn_transparent_union_attribute_field_size_align : Warning< "%select{alignment|size}0 of field %1 (%2 bits) does not match the " "%select{alignment|size}0 of the first field in transparent union; " "transparent_union attribute ignored">, InGroup; def note_transparent_union_first_field_size_align : Note< "%select{alignment|size}0 of first field is %1 bits">; def warn_transparent_union_attribute_not_definition : Warning< "transparent_union attribute can only be applied to a union definition; " "attribute ignored">, InGroup; def warn_transparent_union_attribute_floating : Warning< "first field of a transparent union cannot have %select{floating point|" "vector}0 type %1; transparent_union attribute ignored">, InGroup; def warn_transparent_union_attribute_zero_fields : Warning< "transparent union definition must contain at least one field; " "transparent_union attribute ignored">, InGroup; def warn_attribute_type_not_supported : Warning< "%0 attribute argument not supported: %1">, InGroup; def warn_attribute_unknown_visibility : Warning<"unknown visibility %0">, InGroup; def warn_attribute_protected_visibility : Warning<"target does not support 'protected' visibility; using 'default'">, InGroup>; def err_mismatched_visibility: Error<"visibility does not match previous declaration">; def note_previous_attribute : Note<"previous attribute is here">; def note_conflicting_attribute : Note<"conflicting attribute is here">; def note_attribute : Note<"attribute is here">; def err_mismatched_ms_inheritance : Error< "inheritance model does not match %select{definition|previous declaration}0">; def warn_ignored_ms_inheritance : Warning< "inheritance model ignored on %select{primary template|partial specialization}0">, InGroup; def note_previous_ms_inheritance : Note< "previous inheritance model specified here">; def err_machine_mode : Error<"%select{unknown|unsupported}0 machine mode %1">; def err_mode_not_primitive : Error< "mode attribute only supported for integer and floating-point types">; def err_mode_wrong_type : Error< "type of machine mode does not match type of base type">; def err_attr_wrong_decl : Error< "%0 attribute invalid on this declaration, requires typedef or value">; def warn_attribute_nonnull_no_pointers : Warning< "'nonnull' attribute applied to function with no pointer arguments">, InGroup; def warn_attribute_nonnull_parm_no_args : Warning< "'nonnull' attribute when used on parameters takes no arguments">, InGroup; def warn_attribute_malloc_pointer_only : Warning< "'malloc' attribute only applies to functions returning a pointer type">, InGroup; def warn_attribute_sentinel_named_arguments : Warning< "'sentinel' attribute requires named arguments">, InGroup; def warn_attribute_sentinel_not_variadic : Warning< "'sentinel' attribute only supported for variadic %select{functions|blocks}0">, InGroup; def err_attribute_sentinel_less_than_zero : Error< "'sentinel' parameter 1 less than zero">; def err_attribute_sentinel_not_zero_or_one : Error< "'sentinel' parameter 2 not 0 or 1">; def warn_cleanup_ext : Warning< "GCC does not allow the 'cleanup' attribute argument to be anything other " "than a simple identifier">, InGroup; def err_attribute_cleanup_arg_not_function : Error< "'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">; def err_attribute_cleanup_func_must_take_one_arg : Error< "'cleanup' function %0 must take 1 parameter">; def err_attribute_cleanup_func_arg_incompatible_type : Error< "'cleanup' function %0 parameter has " "%diff{type $ which is incompatible with type $|incompatible type}1,2">; def err_attribute_regparm_wrong_platform : Error< "'regparm' is not valid on this platform">; def err_attribute_regparm_invalid_number : Error< "'regparm' parameter must be between 0 and %0 inclusive">; def err_attribute_not_supported_in_lang : Error< "%0 attribute is not supported in %select{C|C++|Objective-C}1">; // Clang-Specific Attributes def warn_attribute_iboutlet : Warning< "%0 attribute can only be applied to instance variables or properties">, InGroup; def err_iboutletcollection_type : Error< "invalid type %0 as argument of iboutletcollection attribute">; def err_iboutletcollection_builtintype : Error< "type argument of iboutletcollection attribute cannot be a builtin type">; def warn_iboutlet_object_type : Warning< "%select{instance variable|property}2 with %0 attribute must " "be an object type (invalid %1)">, InGroup; def warn_iboutletcollection_property_assign : Warning< "IBOutletCollection properties should be copy/strong and not assign">, InGroup; def err_attribute_overloadable_missing : Error< "%select{overloaded function|redeclaration of}0 %1 must have the " "'overloadable' attribute">; def note_attribute_overloadable_prev_overload : Note< "previous overload of function is here">; def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; def warn_ns_attribute_wrong_return_type : Warning< "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, InGroup; def warn_ns_attribute_wrong_parameter_type : Warning< "%0 attribute only applies to %select{Objective-C object|pointer}1 " "parameters">, InGroup; def warn_objc_requires_super_protocol : Warning< "%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">, InGroup>; def note_protocol_decl : Note< "protocol is declared here">; def note_protocol_decl_undefined : Note< "protocol %0 has no definition">; // objc_designated_initializer attribute diagnostics. def warn_objc_designated_init_missing_super_call : Warning< "designated initializer missing a 'super' call to a designated initializer of the super class">, InGroup; def note_objc_designated_init_marked_here : Note< "method marked as designated initializer of the class here">; def warn_objc_designated_init_non_super_designated_init_call : Warning< "designated initializer should only invoke a designated initializer on 'super'">, InGroup; def warn_objc_designated_init_non_designated_init_call : Warning< "designated initializer invoked a non-designated initializer">, InGroup; def warn_objc_secondary_init_super_init_call : Warning< "convenience initializer should not invoke an initializer on 'super'">, InGroup; def warn_objc_secondary_init_missing_init_call : Warning< "convenience initializer missing a 'self' call to another initializer">, InGroup; def warn_objc_implementation_missing_designated_init_override : Warning< "method override for the designated initializer of the superclass %objcinstance0 not found">, InGroup; // objc_bridge attribute diagnostics. def err_objc_attr_not_id : Error< "parameter of %0 attribute must be a single name of an Objective-C %select{class|protocol}1">; def err_objc_cf_bridged_not_interface : Error< "CF object of type %0 is bridged to %1, which is not an Objective-C class">; def err_objc_ns_bridged_invalid_cfobject : Error< "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">; def warn_objc_invalid_bridge : Warning< "%0 bridges to %1, not %2">, InGroup; def warn_objc_invalid_bridge_to_cf : Warning< "%0 cannot bridge to %1">, InGroup; // objc_bridge_related attribute diagnostics. def err_objc_bridged_related_invalid_class : Error< "could not find Objective-C class %0 to convert %1 to %2">; def err_objc_bridged_related_invalid_class_name : Error< "%0 must be name of an Objective-C class to be able to convert %1 to %2">; def err_objc_bridged_related_known_method : Error< "%0 must be explicitly converted to %1; use %select{%objcclass2|%objcinstance2}3 " "method for this conversion">; def err_objc_attr_protocol_requires_definition : Error< "attribute %0 can only be applied to @protocol definitions, not forward declarations">; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; def err_void_only_param : Error< "'void' must be the first and only parameter if specified">; def err_void_param_qualified : Error< "'void' as parameter must not have type qualifiers">; def err_ident_list_in_fn_declaration : Error< "a parameter list without types is only allowed in a function definition">; def ext_param_not_declared : Extension< "parameter %0 was not declared, defaulting to type 'int'">; def err_param_default_argument : Error< "C does not support default arguments">; def err_param_default_argument_redefinition : Error< "redefinition of default argument">; def ext_param_default_argument_redefinition : ExtWarn< "redefinition of default argument">, InGroup; def err_param_default_argument_missing : Error< "missing default argument on parameter">; def err_param_default_argument_missing_name : Error< "missing default argument on parameter %0">; def err_param_default_argument_references_param : Error< "default argument references parameter %0">; def err_param_default_argument_references_local : Error< "default argument references local variable %0 of enclosing function">; def err_param_default_argument_references_this : Error< "default argument references 'this'">; def err_param_default_argument_nonfunc : Error< "default arguments can only be specified for parameters in a function " "declaration">; def err_param_default_argument_template_redecl : Error< "default arguments cannot be added to a function template that has already " "been declared">; def err_param_default_argument_member_template_redecl : Error< "default arguments cannot be added to an out-of-line definition of a member " "of a %select{class template|class template partial specialization|nested " "class in a template}0">; def err_uninitialized_member_for_assign : Error< "cannot define the implicit copy assignment operator for %0, because " "non-static %select{reference|const}1 member %2 can't use copy " "assignment operator">; def err_uninitialized_member_in_ctor : Error< "%select{|implicit default |inheriting }0constructor for %1 must explicitly " "initialize the %select{reference|const}2 member %3">; def err_default_arg_makes_ctor_special : Error< "addition of default argument on redeclaration makes this constructor a " "%select{default|copy|move}0 constructor">; def err_use_of_default_argument_to_function_declared_later : Error< "use of default argument to function %0 that is declared later in class %1">; def note_default_argument_declared_here : Note< "default argument declared here">; def ext_param_promoted_not_compatible_with_prototype : ExtWarn< "%diff{promoted type $ of K&R function parameter is not compatible with the " "parameter type $|promoted type of K&R function parameter is not compatible " "with parameter type}0,1 declared in a previous prototype">, InGroup; // C++ Overloading Semantic Analysis. def err_ovl_diff_return_type : Error< "functions that differ only in their return type cannot be overloaded">; def err_ovl_static_nonstatic_member : Error< "static and non-static member functions with the same parameter types " "cannot be overloaded">; def err_ovl_no_viable_function_in_call : Error< "no matching function for call to %0">; def err_ovl_no_viable_member_function_in_call : Error< "no matching member function for call to %0">; def err_ovl_ambiguous_call : Error< "call to %0 is ambiguous">; def err_ovl_deleted_call : Error< "call to %select{unavailable|deleted}0 function %1%2">; def err_ovl_ambiguous_member_call : Error< "call to member function %0 is ambiguous">; def err_ovl_deleted_member_call : Error< "call to %select{unavailable|deleted}0 member function %1%2">; def note_ovl_too_many_candidates : Note< "remaining %0 candidate%s0 omitted; " "pass -fshow-overloads=all to show them">; def note_ovl_candidate : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "is the implicit default constructor|" "is the implicit copy constructor|" "is the implicit move constructor|" "is the implicit copy assignment operator|" "is the implicit move assignment operator|" "is an inherited constructor}0%1" "%select{| has different class%diff{ (expected $ but has $)|}3,4" "| has different number of parameters (expected %3 but has %4)" "| has type mismatch at %ordinal3 parameter" "%diff{ (expected $ but has $)|}4,5" "| has different return type%diff{ ($ expected but has $)|}3,4" "| has different qualifiers (expected " "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}3 but found " "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}4)}2">; def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; def note_ovl_candidate_illegal_constructor : Note< "candidate %select{constructor|template}0 ignored: " "instantiation %select{takes|would take}0 its own class type by value">; def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; def note_ovl_candidate_inconsistent_deduction : Note< "candidate template ignored: deduced conflicting %select{types|values|" "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">; def note_ovl_candidate_explicit_arg_mismatch_named : Note< "candidate template ignored: invalid explicitly-specified argument " "for template parameter %0">; def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< "candidate template ignored: invalid explicitly-specified argument " "for %ordinal0 template parameter">; def note_ovl_candidate_instantiation_depth : Note< "candidate template ignored: substitution exceeded maximum template " "instantiation depth">; def note_ovl_candidate_underqualified : Note< "candidate template ignored: can't deduce a type for %0 that would " "make %2 equal %1">; def note_ovl_candidate_substitution_failure : Note< "candidate template ignored: substitution failure%0%1">; def note_ovl_candidate_disabled_by_enable_if : Note< "candidate template ignored: disabled by %0%1">; def note_ovl_candidate_disabled_by_enable_if_attr : Note< "candidate disabled: %0">; def note_ovl_candidate_failed_overload_resolution : Note< "candidate template ignored: couldn't resolve reference to overloaded " "function %0">; def note_ovl_candidate_non_deduced_mismatch : Note< "candidate template ignored: could not match %diff{$ against $|types}0,1">; // This note is needed because the above note would sometimes print two // different types with the same name. Remove this note when the above note // can handle that case properly. def note_ovl_candidate_non_deduced_mismatch_qualified : Note< "candidate template ignored: could not match %q0 against %q1">; // Note that we don't treat templates differently for this diagnostic. def note_ovl_candidate_arity : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0 %select{|template }1" "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " "%plural{1:was|:were}4 provided">; def note_ovl_candidate_arity_one : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0 %select{|template }1not viable: " "%select{requires at least|allows at most single|requires single}2 " "argument %3, but %plural{0:no|:%4}4 arguments were provided">; def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 has been " "%select{explicitly made unavailable|explicitly deleted|" "implicitly deleted}2">; // Giving the index of the bad argument really clutters this message, and // it's relatively unimportant because 1) it's generally obvious which // argument(s) are of the given object type and 2) the fix is usually // to complete the type, which doesn't involve changes to the call line // anyway. If people complain, we can change it. def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 " "not viable: cannot convert argument of incomplete type " "%diff{$ to $|to parameter type}2,3">; def note_ovl_candidate_bad_list_argument : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 " "not viable: cannot convert initializer list argument to %3">; def note_ovl_candidate_bad_overload : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" " not viable: no known conversion " "%diff{from $ to $|from argument type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" "%select{|; dereference the argument with *|" "; take the address of the argument with &|" "; remove *|" "; remove &}6">; def note_ovl_candidate_bad_arc_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" " not viable: cannot implicitly convert argument " "%diff{of type $ to $|type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4 under ARC">; def note_ovl_candidate_bad_lvalue : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" " not viable: expects an l-value for " "%select{%ordinal3 argument|object argument}2">; def note_ovl_candidate_bad_addrspace : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; def note_ovl_candidate_bad_gc : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; def note_ovl_candidate_bad_ownership : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has " "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}4 ownership">; def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function|||||" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|}0 not viable: " "'this' argument has type %2, but method is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}3">; def note_ovl_candidate_bad_cvr : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1 not viable: " "%ordinal4 argument (%2) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3 qualifier" "%select{||s||s|s|s}3">; def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0%1" " not viable: cannot %select{convert from|convert from|bind}2 " "%select{base class pointer|superclass|base class object of type}2 %3 to " "%select{derived class pointer|subclass|derived class reference}2 %4 for " "%ordinal5 argument">; def note_ovl_candidate_bad_target : Note< "candidate %select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "constructor (inherited)}0 not viable: call to " "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; def note_implicit_member_target_infer_collision : Note< "implicit %select{" "default constructor|" "copy constructor|" "move constructor|" "copy assignment operator|" "move assignment operator|" "destructor}0 inferred target collision: call to both " "%select{__device__|__global__|__host__|__host__ __device__}1 and " "%select{__device__|__global__|__host__|__host__ __device__}2 members">; def note_ambiguous_type_conversion: Note< "because of ambiguity in conversion %diff{of $ to $|between types}0,1">; def note_ovl_builtin_binary_candidate : Note< "built-in candidate %0">; def note_ovl_builtin_unary_candidate : Note< "built-in candidate %0">; def err_ovl_no_viable_function_in_init : Error< "no matching constructor for initialization of %0">; def err_ovl_no_conversion_in_cast : Error< "cannot convert %1 to %2 without a conversion operator">; def err_ovl_no_viable_conversion_in_cast : Error< "no matching conversion for %select{|static_cast|reinterpret_cast|" "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; def err_ovl_ambiguous_conversion_in_cast : Error< "ambiguous conversion for %select{|static_cast|reinterpret_cast|" "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; def err_ovl_deleted_conversion_in_cast : Error< "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 uses deleted function">; def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; def err_ref_init_ambiguous : Error< "reference initialization of type %0 with initializer of type %1 is ambiguous">; def err_ovl_deleted_init : Error< "call to %select{unavailable|deleted}0 constructor of %1">; def err_ovl_deleted_special_init : Error< "call to implicitly-deleted %select{default constructor|copy constructor|" "move constructor|copy assignment operator|move assignment operator|" "destructor|function}0 of %1">; def err_ovl_ambiguous_oper_unary : Error< "use of overloaded operator '%0' is ambiguous (operand type %1)">; def err_ovl_ambiguous_oper_binary : Error< "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; def note_assign_lhs_incomplete : Note<"type %0 is incomplete">; def err_ovl_deleted_oper : Error< "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; def err_ovl_deleted_special_oper : Error< "object of type %0 cannot be %select{constructed|copied|moved|assigned|" "assigned|destroyed}1 because its %select{default constructor|" "copy constructor|move constructor|copy assignment operator|" "move assignment operator|destructor}1 is implicitly deleted">; def err_ovl_no_viable_subscript : Error<"no viable overloaded operator[] for type %0">; def err_ovl_no_oper : Error<"type %0 does not provide a %select{subscript|call}1 operator">; def err_ovl_unresolvable : Error< "reference to overloaded function could not be resolved; " "did you mean to call it%select{| with no arguments}0?">; def err_bound_member_function : Error< "reference to non-static member function must be called" "%select{|; did you mean to call it with no arguments?}0">; def note_possible_target_of_call : Note<"possible target for call">; def err_ovl_no_viable_object_call : Error< "no matching function for call to object of type %0">; def err_ovl_ambiguous_object_call : Error< "call to object of type %0 is ambiguous">; def err_ovl_deleted_object_call : Error< "call to %select{unavailable|deleted}0 function call operator in type %1%2">; def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to non-static member function without an object argument">; // C++ Address of Overloaded Function def err_addr_ovl_no_viable : Error< "address of overloaded function %0 does not match required type %1">; def err_addr_ovl_ambiguous : Error< "address of overloaded function %0 is ambiguous">; def err_addr_ovl_not_func_ptrref : Error< "address of overloaded function %0 cannot be converted to type %1">; def err_addr_ovl_no_qualifier : Error< "can't form member pointer of type %0 without '&' and class name">; // C++11 Literal Operators def err_ovl_no_viable_literal_operator : Error< "no matching literal operator for call to %0" "%select{| with argument of type %2| with arguments of types %2 and %3}1" "%select{| or 'const char *'}4" "%select{|, and no matching literal operator template}5">; // C++ Template Declarations def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def note_template_param_here : Note<"template parameter is declared here">; def warn_template_export_unsupported : Warning< "exported templates are unsupported">; def err_template_outside_namespace_or_class_scope : Error< "templates can only be declared in namespace or class scope">; def err_template_inside_local_class : Error< "templates cannot be declared inside of a local class">; def err_template_linkage : Error<"templates must have C++ linkage">; def err_template_typedef : Error<"a typedef cannot be a template">; def err_template_unnamed_class : Error< "cannot declare a class template with no name">; def err_template_param_list_different_arity : Error< "%select{too few|too many}0 template parameters in template " "%select{|template parameter }1redeclaration">; def note_template_param_list_different_arity : Note< "%select{too few|too many}0 template parameters in template template " "argument">; def note_template_prev_declaration : Note< "previous template %select{declaration|template parameter}0 is here">; def err_template_param_different_kind : Error< "template parameter has a different kind in template " "%select{|template parameter }0redeclaration">; def note_template_param_different_kind : Note< "template parameter has a different kind in template argument">; def err_template_nontype_parm_different_type : Error< "template non-type parameter has a different type %0 in template " "%select{|template parameter }1redeclaration">; def note_template_nontype_parm_different_type : Note< "template non-type parameter has a different type %0 in template argument">; def note_template_nontype_parm_prev_declaration : Note< "previous non-type template parameter with type %0 is here">; def err_template_nontype_parm_bad_type : Error< "a non-type template parameter cannot have type %0">; def err_template_param_default_arg_redefinition : Error< "template parameter redefines default argument">; def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; def ext_template_parameter_default_in_function_template : ExtWarn< "default template arguments for a function template are a C++11 extension">, InGroup; def warn_cxx98_compat_template_parameter_default_in_function_template : Warning< "default template arguments for a function template are incompatible with C++98">, InGroup, DefaultIgnore; def err_template_parameter_default_template_member : Error< "cannot add a default template argument to the definition of a member of a " "class template">; def err_template_parameter_default_friend_template : Error< "default template argument not permitted on a friend template">; def err_template_template_parm_no_parms : Error< "template template parameter must have its own template parameters">; def ext_variable_template : ExtWarn<"variable templates are a C++14 extension">, InGroup; def warn_cxx11_compat_variable_template : Warning< "variable templates are incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; def err_template_member : Error<"member %0 declared as a template">; def err_template_member_noparams : Error< "extraneous 'template<>' in declaration of member %0">; def err_template_tag_noparams : Error< "extraneous 'template<>' in declaration of %0 %1">; def err_template_decl_ref : Error< "cannot refer to %select{class|variable}0 template %1 without a template argument list">; // C++ Template Argument Lists def err_template_missing_args : Error< "use of class template %0 requires template arguments">; def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " "%select{class template|function template|template template parameter" "|template}1 %2">; def note_template_decl_here : Note<"template is declared here">; def err_template_arg_must_be_type : Error< "template argument for template type parameter must be a type">; def err_template_arg_must_be_type_suggest : Error< "template argument for template type parameter must be a type; did you forget 'typename'?">; def ext_ms_template_type_arg_missing_typename : ExtWarn< "template argument for template type parameter must be a type; " "omitted 'typename' is a Microsoft extension">, InGroup; def err_template_arg_must_be_expr : Error< "template argument for non-type template parameter must be an expression">; def err_template_arg_nontype_ambig : Error< "template argument for non-type template parameter is treated as function type %0">; def err_template_arg_must_be_template : Error< "template argument for template template parameter must be a class template%select{| or type alias template}0">; def ext_template_arg_local_type : ExtWarn< "template argument uses local type %0">, InGroup; def ext_template_arg_unnamed_type : ExtWarn< "template argument uses unnamed type">, InGroup; def warn_cxx98_compat_template_arg_local_type : Warning< "local type %0 as template argument is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_template_arg_unnamed_type : Warning< "unnamed type as template argument is incompatible with C++98">, InGroup, DefaultIgnore; def note_template_unnamed_type_here : Note< "unnamed type used in template argument was declared here">; def err_template_arg_overload_type : Error< "template argument is the type of an unresolved overloaded function">; def err_template_arg_not_class_template : Error< "template argument does not refer to a class template or template " "template parameter">; def note_template_arg_refers_here_func : Note< "template argument refers to function template %0, here">; def err_template_arg_template_params_mismatch : Error< "template template argument has different template parameters than its " "corresponding template template parameter">; def err_template_arg_not_integral_or_enumeral : Error< "non-type template argument of type %0 must have an integral or enumeration" " type">; def err_template_arg_not_ice : Error< "non-type template argument of type %0 is not an integral constant " "expression">; def err_template_arg_not_address_constant : Error< "non-type template argument of type %0 is not a constant expression">; def warn_cxx98_compat_template_arg_null : Warning< "use of null pointer as non-type template argument is incompatible with " "C++98">, InGroup, DefaultIgnore; def err_template_arg_untyped_null_constant : Error< "null non-type template argument must be cast to template parameter type %0">; def err_template_arg_wrongtype_null_constant : Error< "null non-type template argument of type %0 does not match template parameter " "of type %1">; def err_deduced_non_type_template_arg_type_mismatch : Error< "deduced non-type template argument does not have the same type as the " "its corresponding template parameter%diff{ ($ vs $)|}0,1">; def err_non_type_template_arg_subobject : Error< "non-type template argument refers to subobject '%0'">; def err_non_type_template_arg_addr_label_diff : Error< "template argument / label address difference / what did you expect?">; def err_template_arg_not_convertible : Error< "non-type template argument of type %0 cannot be converted to a value " "of type %1">; def warn_template_arg_negative : Warning< "non-type template argument with value '%0' converted to '%1' for unsigned " "template parameter of type %2">, InGroup, DefaultIgnore; def warn_template_arg_too_large : Warning< "non-type template argument value '%0' truncated to '%1' for " "template parameter of type %2">, InGroup, DefaultIgnore; def err_template_arg_no_ref_bind : Error< "non-type template parameter of reference type " "%diff{$ cannot bind to template argument of type $" "|cannot bind to template of incompatible argument type}0,1">; def err_template_arg_ref_bind_ignores_quals : Error< "reference binding of non-type template parameter " "%diff{of type $ to template argument of type $|to template argument}0,1 " "ignores qualifiers">; def err_template_arg_not_decl_ref : Error< "non-type template argument does not refer to any declaration">; def err_template_arg_not_address_of : Error< "non-type template argument for template parameter of pointer type %0 must " "have its address taken">; def err_template_arg_address_of_non_pointer : Error< "address taken in non-type template argument for template parameter of " "reference type %0">; def err_template_arg_reference_var : Error< "non-type template argument of reference type %0 is not an object">; def err_template_arg_field : Error< "non-type template argument refers to non-static data member %0">; def err_template_arg_method : Error< "non-type template argument refers to non-static member function %0">; def err_template_arg_object_no_linkage : Error< "non-type template argument refers to %select{function|object}0 %1 that " "does not have linkage">; def warn_cxx98_compat_template_arg_object_internal : Warning< "non-type template argument referring to %select{function|object}0 %1 with " "internal linkage is incompatible with C++98">, InGroup, DefaultIgnore; def ext_template_arg_object_internal : ExtWarn< "non-type template argument referring to %select{function|object}0 %1 with " "internal linkage is a C++11 extension">, InGroup; def err_template_arg_thread_local : Error< "non-type template argument refers to thread-local object">; def note_template_arg_internal_object : Note< "non-type template argument refers to %select{function|object}0 here">; def note_template_arg_refers_here : Note< "non-type template argument refers here">; def err_template_arg_not_object_or_func : Error< "non-type template argument does not refer to an object or function">; def err_template_arg_not_pointer_to_member_form : Error< "non-type template argument is not a pointer to member constant">; def err_template_arg_member_ptr_base_derived_not_supported : Error< "sorry, non-type template argument of pointer-to-member type %1 that refers " "to member %q0 of a different class is not supported yet">; def ext_template_arg_extra_parens : ExtWarn< "address non-type template argument cannot be surrounded by parentheses">; def warn_cxx98_compat_template_arg_extra_parens : Warning< "redundant parentheses surrounding address non-type template argument are " "incompatible with C++98">, InGroup, DefaultIgnore; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; def err_pointer_to_member_call_drops_quals : Error< "call to pointer to member function of type %0 drops '%1' qualifier%s2">; def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup; def ext_ms_delayed_template_argument: ExtWarn< "using the undeclared type %0 as a default template argument is a " "Microsoft extension">, InGroup; // C++ template specialization def err_template_spec_unknown_kind : Error< "can only provide an explicit specialization for a class template, function " "template, variable template, or a member function, static data member, " "%select{or member class|member class, or member enumeration}0 of a " "class template">; def note_specialized_entity : Note< "explicitly specialized declaration is here">; def err_template_spec_decl_function_scope : Error< "explicit specialization of %0 in function scope">; def err_template_spec_decl_class_scope : Error< "explicit specialization of %0 in class scope">; def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; def err_template_spec_decl_out_of_scope_global : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member function|" "static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in the global scope">; def err_template_spec_decl_out_of_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in namespace %2">; def ext_template_spec_decl_out_of_scope : ExtWarn< "first declaration of %select{class template|class template partial|" "variable template|variable template partial|" "function template|member function|static data member|member class|" "member enumeration}0 specialization of %1 outside namespace %2 is a " "C++11 extension">, InGroup; def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 outside namespace %2 is incompatible with C++98">, InGroup, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 not in a namespace enclosing %2">; def err_template_spec_redecl_global_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must occur at global scope">; def err_spec_member_not_instantiated : Error< "specialization of member %q0 does not specialize an instantiated member">; def note_specialized_decl : Note<"attempt to specialize declaration here">; def err_specialization_after_instantiation : Error< "explicit specialization of %0 after instantiation">; def note_instantiation_required_here : Note< "%select{implicit|explicit}0 instantiation first required here">; def err_template_spec_friend : Error< "template specialization declaration cannot be a friend">; def err_template_spec_default_arg : Error< "default argument not permitted on an explicit " "%select{instantiation|specialization}0 of function %1">; def err_not_class_template_specialization : Error< "cannot specialize a %select{dependent template|template template " "parameter}0">; def err_function_specialization_in_class : Error< "cannot specialize a function %0 within class scope">; def ext_function_specialization_in_class : ExtWarn< "explicit specialization of %0 within class scope is a Microsoft extension">, InGroup; def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">; def err_explicit_specialization_inconsistent_storage_class : Error< "explicit specialization has extraneous, inconsistent storage class " "'%select{none|extern|static|__private_extern__|auto|register}0'">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< "template specialization requires 'template<>'">; def err_template_spec_needs_template_parameters : Error< "template specialization or definition requires a template parameter list " "corresponding to the nested type %0">; def err_template_param_list_matches_nontemplate : Error< "template parameter list matching the non-templated nested type %0 should " "be empty ('template<>')">; def err_alias_template_extra_headers : Error< "extraneous template parameter list in alias template declaration">; def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; def warn_template_spec_extra_headers : Warning< "extraneous template parameter list in template specialization">; def note_explicit_template_spec_does_not_need_header : Note< "'template<>' header not required for explicitly-specialized class %0 " "declared here">; def err_template_qualified_declarator_no_match : Error< "nested name specifier '%0' for declaration does not refer into a class, " "class template or class template partial specialization">; def err_specialize_member_of_template : Error< "cannot specialize %select{|(with 'template<>') }0a member of an " "unspecialized template">; // C++ Class Template Partial Specialization def err_default_arg_in_partial_spec : Error< "default template argument in a class template partial specialization">; def err_dependent_non_type_arg_in_partial_spec : Error< "non-type template argument depends on a template parameter of the " "partial specialization">; def note_dependent_non_type_default_arg_in_partial_spec : Note< "template parameter is used in default argument declared here">; def err_dependent_typed_non_type_arg_in_partial_spec : Error< "non-type template argument specializes a template parameter with " "dependent type %0">; def err_partial_spec_args_match_primary_template : Error< "%select{class|variable}0 template partial specialization does not " "specialize any template argument; to %select{declare|define}1 the " "primary template, remove the template argument list">; def warn_partial_specs_not_deducible : Warning< "%select{class|variable}0 template partial specialization contains " "%select{a template parameter|template parameters}1 that cannot be " "deduced; this partial specialization will never be used">; def note_partial_spec_unused_parameter : Note< "non-deducible template parameter %0">; def err_partial_spec_ordering_ambiguous : Error< "ambiguous partial specializations of %0">; def note_partial_spec_match : Note<"partial specialization matches %0">; def err_partial_spec_redeclared : Error< "class template partial specialization %0 cannot be redeclared">; def note_prev_partial_spec_here : Note< "previous declaration of class template partial specialization %0 is here">; def err_partial_spec_fully_specialized : Error< "partial specialization of %0 does not use any of its template parameters">; // C++ Variable Template Partial Specialization def err_var_partial_spec_redeclared : Error< "variable template partial specialization %0 cannot be redefined">; def note_var_prev_partial_spec_here : Note< "previous declaration of variable template partial specialization is here">; def err_var_spec_no_template : Error< "no variable template matches%select{| partial}0 specialization">; def err_var_spec_no_template_but_method : Error< "no variable template matches specialization; " "did you mean to use %0 as function template instead?">; // C++ Function template specializations def err_function_template_spec_no_match : Error< "no function template matches function template specialization %0">; def err_function_template_spec_ambiguous : Error< "function template specialization %0 ambiguously refers to more than one " "function template; explicitly specify%select{| additional}1 template " "arguments to identify a particular function template">; def note_function_template_spec_matched : Note< "function template matches specialization %0">; def err_function_template_partial_spec : Error< "function template partial specialization is not allowed">; // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< "recursive template instantiation exceeded maximum depth of %0">, DefaultFatal, NoSFINAE; def note_template_recursion_depth : Note< "use -ftemplate-depth=N to increase recursive template instantiation depth">; def err_template_instantiate_within_definition : Error< "%select{implicit|explicit}0 instantiation of template %1 within its" " own definition">; def err_template_instantiate_undefined : Error< "%select{implicit|explicit}0 instantiation of undefined template %1">; def err_implicit_instantiate_member_undefined : Error< "implicit instantiation of undefined member %0">; def note_template_class_instantiation_was_here : Note< "class template %0 was instantiated here">; def note_template_class_explicit_specialization_was_here : Note< "class template %0 was explicitly specialized here">; def note_template_class_instantiation_here : Note< "in instantiation of template class %0 requested here">; def note_template_member_class_here : Note< "in instantiation of member class %0 requested here">; def note_template_member_function_here : Note< "in instantiation of member function %q0 requested here">; def note_function_template_spec_here : Note< "in instantiation of function template specialization %q0 requested here">; def note_template_static_data_member_def_here : Note< "in instantiation of static data member %q0 requested here">; def note_template_variable_def_here : Note< "in instantiation of variable template specialization %q0 requested here">; def note_template_enum_def_here : Note< "in instantiation of enumeration %q0 requested here">; def note_template_nsdmi_here : Note< "in instantiation of default member initializer %q0 requested here">; def note_template_type_alias_instantiation_here : Note< "in instantiation of template type alias %0 requested here">; def note_template_exception_spec_instantiation_here : Note< "in instantiation of exception specification for %0 requested here">; def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; def note_default_function_arg_instantiation_here : Note< "in instantiation of default function argument expression " "for '%0' required here">; def note_explicit_template_arg_substitution_here : Note< "while substituting explicitly-specified template arguments into function " "template %0 %1">; def note_function_template_deduction_instantiation_here : Note< "while substituting deduced template arguments into function template %0 " "%1">; def note_partial_spec_deduct_instantiation_here : Note< "during template argument deduction for class template partial " "specialization %0 %1">; def note_prior_template_arg_substitution : Note< "while substituting prior template arguments into %select{non-type|template}0" " template parameter%1 %2">; def note_template_default_arg_checking : Note< "while checking a default template argument used here">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; def err_field_instantiates_to_function : Error< "data member instantiated with function type %0">; def err_variable_instantiates_to_function : Error< "%select{variable|static data member}0 instantiated with function type %1">; def err_nested_name_spec_non_tag : Error< "type %0 cannot be used prior to '::' because it has no members">; // C++ Explicit Instantiation def err_explicit_instantiation_duplicate : Error< "duplicate explicit instantiation of %0">; def ext_explicit_instantiation_duplicate : ExtWarn< "duplicate explicit instantiation of %0 ignored as a Microsoft extension">, InGroup; def note_previous_explicit_instantiation : Note< "previous explicit instantiation is here">; def ext_explicit_instantiation_after_specialization : Extension< "explicit instantiation of %0 that occurs after an explicit " "specialization will be ignored (C++11 extension)">, InGroup; def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning< "explicit instantiation of %0 that occurs after an explicit " "specialization is incompatible with C++98">, InGroup, DefaultIgnore; def note_previous_template_specialization : Note< "previous template specialization is here">; def err_explicit_instantiation_nontemplate_type : Error< "explicit instantiation of non-templated type %0">; def note_nontemplate_decl_here : Note< "non-templated declaration is here">; def err_explicit_instantiation_in_class : Error< "explicit instantiation of %0 in class scope">; def err_explicit_instantiation_out_of_scope : Error< "explicit instantiation of %0 not in a namespace enclosing %1">; def err_explicit_instantiation_must_be_global : Error< "explicit instantiation of %0 must occur at global scope">; def warn_explicit_instantiation_out_of_scope_0x : Warning< "explicit instantiation of %0 not in a namespace enclosing %1">, InGroup, DefaultIgnore; def warn_explicit_instantiation_must_be_global_0x : Warning< "explicit instantiation of %0 must occur at global scope">, InGroup, DefaultIgnore; def err_explicit_instantiation_requires_name : Error< "explicit instantiation declaration requires a name">; def err_explicit_instantiation_of_typedef : Error< "explicit instantiation of typedef %0">; def err_explicit_instantiation_storage_class : Error< "explicit instantiation cannot have a storage class">; def err_explicit_instantiation_not_known : Error< "explicit instantiation of %0 does not refer to a function template, " "variable template, member function, member class, or static data member">; def note_explicit_instantiation_here : Note< "explicit instantiation refers here">; def err_explicit_instantiation_data_member_not_instantiated : Error< "explicit instantiation refers to static data member %q0 that is not an " "instantiation">; def err_explicit_instantiation_member_function_not_instantiated : Error< "explicit instantiation refers to member function %q0 that is not an " "instantiation">; def err_explicit_instantiation_ambiguous : Error< "partial ordering for explicit instantiation of %0 is ambiguous">; def note_explicit_instantiation_candidate : Note< "explicit instantiation candidate function template here %0">; def err_explicit_instantiation_inline : Error< "explicit instantiation cannot be 'inline'">; def warn_explicit_instantiation_inline_0x : Warning< "explicit instantiation cannot be 'inline'">, InGroup, DefaultIgnore; def err_explicit_instantiation_constexpr : Error< "explicit instantiation cannot be 'constexpr'">; def ext_explicit_instantiation_without_qualified_id : Extension< "qualifier in explicit instantiation of %q0 requires a template-id " "(a typedef is not permitted)">; def err_explicit_instantiation_without_template_id : Error< "explicit instantiation of %q0 must specify a template argument list">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< "explicit instantiation of %q0 must occur in namespace %1">; def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< "explicit instantiation of %q0 must occur in namespace %1">, InGroup, DefaultIgnore; def err_explicit_instantiation_undefined_member : Error< "explicit instantiation of undefined %select{member class|member function|" "static data member}0 %1 of class template %2">; def err_explicit_instantiation_undefined_func_template : Error< "explicit instantiation of undefined function template %0">; def err_explicit_instantiation_undefined_var_template : Error< "explicit instantiation of undefined variable template %q0">; def err_explicit_instantiation_declaration_after_definition : Error< "explicit instantiation declaration (with 'extern') follows explicit " "instantiation definition (without 'extern')">; def note_explicit_instantiation_definition_here : Note< "explicit instantiation definition is here">; def err_invalid_var_template_spec_type : Error<"type %2 " "of %select{explicit instantiation|explicit specialization|" "partial specialization|redeclaration}0 of %1 does not match" " expected type %3">; def err_mismatched_exception_spec_explicit_instantiation : Error< "exception specification in explicit instantiation does not match instantiated one">; def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< "exception specification in explicit instantiation does not match instantiated one">, InGroup; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_enable_if : Error< "no type named 'type' in %0; 'enable_if' cannot be used to disable " "this declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; def note_typename_refers_here : Note< "referenced member %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; def ext_typename_missing : ExtWarn< "missing 'typename' prior to dependent type name '%0%1'">, InGroup>; def ext_typename_outside_of_template : ExtWarn< "'typename' occurs outside of a template">, InGroup; def warn_cxx98_compat_typename_outside_of_template : Warning< "use of 'typename' outside of a template is incompatible with C++98">, InGroup, DefaultIgnore; def err_typename_refers_to_using_value_decl : Error< "typename specifier refers to a dependent using declaration for a value " "%0 in %1">; def note_using_value_decl_missing_typename : Note< "add 'typename' to treat this using declaration as a type">; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; def err_template_kw_refers_to_class_template : Error< "'%0%1' instantiated to a class template, not a function template">; def note_referenced_class_template : Error< "class template declared here">; def err_template_kw_missing : Error< "missing 'template' keyword prior to dependent template name '%0%1'">; def ext_template_outside_of_template : ExtWarn< "'template' keyword outside of a template">, InGroup; def warn_cxx98_compat_template_outside_of_template : Warning< "use of 'template' keyword outside of a template is incompatible with C++98">, InGroup, DefaultIgnore; def err_non_type_template_in_nested_name_specifier : Error< "qualified name refers into a specialization of %select{function|variable}0 " "template %1">; def err_template_id_not_a_type : Error< "template name refers to non-type template %0">; def note_template_declared_here : Note< "%select{function template|class template|variable template" "|type alias template|template template parameter}0 " "%1 declared here">; def err_alias_template_expansion_into_fixed_list : Error< "pack expansion used as argument for non-pack parameter of alias template">; def note_parameter_type : Note< "parameter of type %0 is declared here">; // C++11 Variadic Templates def err_template_param_pack_default_arg : Error< "template parameter pack cannot have a default argument">; def err_template_param_pack_must_be_last_template_parameter : Error< "template parameter pack must be the last template parameter">; def err_template_parameter_pack_non_pack : Error< "%select{template type|non-type template|template template}0 parameter" "%select{| pack}1 conflicts with previous %select{template type|" "non-type template|template template}0 parameter%select{ pack|}1">; def note_template_parameter_pack_non_pack : Note< "%select{template type|non-type template|template template}0 parameter" "%select{| pack}1 does not match %select{template type|non-type template" "|template template}0 parameter%select{ pack|}1 in template argument">; def note_template_parameter_pack_here : Note< "previous %select{template type|non-type template|template template}0 " "parameter%select{| pack}1 declared here">; def err_unexpanded_parameter_pack_0 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block}0 " "contains an unexpanded parameter pack">; def err_unexpanded_parameter_pack_1 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block}0 " "contains unexpanded parameter pack %1">; def err_unexpanded_parameter_pack_2 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block}0 " "contains unexpanded parameter packs %1 and %2">; def err_unexpanded_parameter_pack_3_or_more : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block}0 " "contains unexpanded parameter packs %1, %2, ...">; def err_pack_expansion_without_parameter_packs : Error< "pack expansion does not contain any unexpanded parameter packs">; def err_pack_expansion_length_conflict : Error< "pack expansion contains parameter packs %0 and %1 that have different " "lengths (%2 vs. %3)">; def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " "length (%1 vs. %2) from outer parameter packs">; def err_pack_expansion_member_init : Error< "pack expansion for initialization of member %0">; def err_function_parameter_pack_without_parameter_packs : Error< "type %0 of function parameter pack does not contain any unexpanded " "parameter packs">; def err_ellipsis_in_declarator_not_parameter : Error< "only function and template parameters can be parameter packs">; def err_sizeof_pack_no_pack_name : Error< "%0 does not refer to the name of a parameter pack">; def err_fold_expression_packs_both_sides : Error< "binary fold expression has unexpanded parameter packs in both operands">; def err_fold_expression_empty : Error< "unary fold expression has empty expansion for operator '%0' " "with no fallback value">; def err_fold_expression_bad_operand : Error< "expression not permitted as operand of fold expression">; def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; def err_unexpected_namespace : Error< "unexpected namespace name %0: expected expression">; def err_undeclared_var_use : Error<"use of undeclared identifier %0">; def ext_undeclared_unqual_id_with_dependent_base : ExtWarn< "use of undeclared identifier %0; " "unqualified lookup into dependent bases of class template %1 is a Microsoft extension">, InGroup; def ext_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " "found via unqualified lookup into dependent bases of class templates is a " "Microsoft extension">, InGroup; def note_dependent_var_use : Note<"must qualify identifier to find this " "declaration in dependent base class">; def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " "visible in the template definition nor found by argument-dependent lookup">; def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; def err_undeclared_use : Error<"use of undeclared %0">; def warn_deprecated : Warning<"%0 is deprecated">, InGroup; def warn_property_method_deprecated : Warning<"property access is using %0 method which is deprecated">, InGroup; def warn_deprecated_message : Warning<"%0 is deprecated: %1">, InGroup; def warn_deprecated_anonymous_namespace : Warning< "'deprecated' attribute on anonymous namespace ignored">, InGroup; def warn_deprecated_fwdclass_message : Warning< "%0 may be deprecated because the receiver type is unknown">, InGroup; def warn_deprecated_def : Warning< "Implementing deprecated %select{method|class|category}0">, InGroup, DefaultIgnore; def err_unavailable : Error<"%0 is unavailable">; def err_property_method_unavailable : Error<"property access is using %0 method which is unavailable">; def err_unavailable_message : Error<"%0 is unavailable: %1">; def warn_unavailable_fwdclass_message : Warning< "%0 may be unavailable because the receiver type is unknown">, InGroup; def note_availability_specified_here : Note< "%0 has been explicitly marked " "%select{unavailable|deleted|deprecated}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 note_cannot_inherit : Note< "constructor cannot be inherited">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; def warn_missing_sentinel : Warning < "missing sentinel in %select{function call|method dispatch|block call}0">, InGroup; def note_sentinel_here : Note< "%select{function|method|block}0 has been explicitly marked sentinel here">; def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup>, DefaultIgnore; def note_declaration_not_a_prototype : Note< "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; def warn_missing_variable_declarations : Warning< "no previous extern declaration for non-static variable %0">, InGroup>, DefaultIgnore; def err_static_data_member_reinitialization : Error<"static data member %0 already has an initializer">; def err_redefinition : Error<"redefinition of %0">; def err_alias_after_tentative : Error<"alias definition of %0 after tentative definition">; def err_tentative_after_alias : Error<"tentative definition of %0 after alias definition">; def err_definition_of_implicitly_declared_member : Error< "definition of implicitly declared %select{default constructor|copy " "constructor|move constructor|copy assignment operator|move assignment " "operator|destructor|function}1">; def err_definition_of_explicitly_defaulted_member : Error< "definition of explicitly defaulted %select{default constructor|copy " "constructor|move constructor|copy assignment operator|move assignment " "operator|destructor}0">; def err_redefinition_extern_inline : Error< "redefinition of a 'extern inline' function %0 is not supported in " "%select{C99 mode|C++}1">; def note_deleted_dtor_no_operator_delete : Note< "virtual destructor requires an unambiguous, accessible 'operator delete'">; def note_deleted_special_member_class_subobject : Note< "%select{default constructor|copy constructor|move constructor|" "copy assignment operator|move assignment operator|destructor}0 of " "%1 is implicitly deleted because " "%select{base class %3|%select{||||variant }4field %3}2 has " "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 " "%select{%select{default constructor|copy constructor|move constructor|copy " "assignment operator|move assignment operator|destructor}0|destructor}5" "%select{||s||}4">; def note_deleted_default_ctor_uninit_field : Note< "default constructor of %0 is implicitly deleted because field %1 of " "%select{reference|const-qualified}3 type %2 would not be initialized">; def note_deleted_default_ctor_all_const : Note< "default constructor of %0 is implicitly deleted because all " "%select{data members|data members of an anonymous union member}1" " are const-qualified">; def note_deleted_copy_ctor_rvalue_reference : Note< "copy constructor of %0 is implicitly deleted because field %1 is of " "rvalue reference type %2">; def note_deleted_copy_user_declared_move : Note< "copy %select{constructor|assignment operator}0 is implicitly deleted because" " %1 has a user-declared move %select{constructor|assignment operator}2">; def note_deleted_assign_field : Note< "%select{copy|move}0 assignment operator of %1 is implicitly deleted " "because field %2 is of %select{reference|const-qualified}4 type %3">; // These should be errors. def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, InGroup>; def warn_undefined_inline : Warning<"inline function %q0 is not defined">, InGroup>; def note_used_here : Note<"used here">; def ext_internal_in_extern_inline : ExtWarn< "static %select{function|variable}0 %1 is used in an inline function with " "external linkage">, InGroup; def ext_internal_in_extern_inline_quiet : Extension< "static %select{function|variable}0 %1 is used in an inline function with " "external linkage">, InGroup; def warn_static_local_in_extern_inline : Warning< "non-constant static local variable in inline function may be different " "in different files">, InGroup; def note_convert_inline_to_static : Note< "use 'static' to give inline function %0 internal linkage">; def ext_redefinition_of_typedef : ExtWarn< "redefinition of typedef %0 is a C11 feature">, InGroup >; def err_redefinition_variably_modified_typedef : Error< "redefinition of %select{typedef|type alias}0 for variably-modified type %1">; def err_inline_decl_follows_def : Error< "inline declaration of %0 follows non-inline definition">; def err_inline_declaration_block_scope : Error< "inline declaration of %0 not allowed in block scope">; def err_static_non_static : Error< "static declaration of %0 follows non-static declaration">; def err_different_language_linkage : Error< "declaration of %0 has a different language linkage">; def ext_retained_language_linkage : Extension< "friend function %0 retaining previous language linkage is an extension">, InGroup>; def err_extern_c_global_conflict : Error< "declaration of %1 %select{with C language linkage|in global scope}0 " "conflicts with declaration %select{in global scope|with C language linkage}0">; def note_extern_c_global_conflict : Note< "declared %select{in global scope|with C language linkage}0 here">; def warn_weak_import : Warning < "an already-declared variable is made a weak_import declaration %0">; def ext_static_non_static : Extension< "redeclaring non-static %0 as static is a Microsoft extension">, InGroup; def err_non_static_static : Error< "non-static declaration of %0 follows static declaration">; def err_extern_non_extern : Error< "extern declaration of %0 follows non-extern declaration">; def err_non_extern_extern : Error< "non-extern declaration of %0 follows extern declaration">; def err_non_thread_thread : Error< "non-thread-local declaration of %0 follows thread-local declaration">; def err_thread_non_thread : Error< "thread-local declaration of %0 follows non-thread-local declaration">; def err_thread_thread_different_kind : Error< "thread-local declaration of %0 with %select{static|dynamic}1 initialization " "follows declaration with %select{dynamic|static}1 initialization">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< "redefinition of %0 as different kind of symbol">; def err_redefinition_different_namespace_alias : Error< "redefinition of %0 as an alias for a different namespace">; def note_previous_namespace_alias : Note< "previously defined as an alias for %0">; def warn_forward_class_redefinition : Warning< "redefinition of forward class %0 of a typedef name of an object type is ignored">, InGroup>; def err_redefinition_different_typedef : Error< "%select{typedef|type alias|type alias template}0 " "redefinition with different types%diff{ ($ vs $)|}1,2">; def err_tag_reference_non_tag : Error< "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">; def err_tag_reference_conflict : Error< "implicit declaration introduced by elaborated type conflicts with " "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; def err_dependent_tag_decl : Error< "%select{declaration|definition}0 of " "%select{struct|interface|union|class|enum}1 in a dependent scope">; def err_tag_definition_of_typedef : Error< "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; def err_conflicting_types : Error<"conflicting types for %0">; def err_nested_redefinition : Error<"nested redefinition of %0">; def err_use_with_wrong_tag : Error< "use of %0 with tag type that does not match previous declaration">; def warn_struct_class_tag_mismatch : Warning< "%select{struct|interface|class}0%select{| template}1 %2 was previously " "declared as a %select{struct|interface|class}3%select{| template}1">, InGroup, DefaultIgnore; def warn_struct_class_previous_tag_mismatch : Warning< "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 " "here but previously declared as " "%select{a struct|an interface|a class}3%select{| template}1">, InGroup, DefaultIgnore; def note_struct_class_suggestion : Note< "did you mean %select{struct|interface|class}0 here?">; def ext_forward_ref_enum : Extension< "ISO C forbids forward references to 'enum' types">; def err_forward_ref_enum : Error< "ISO C++ forbids forward references to 'enum' types">; def ext_ms_forward_ref_enum : Extension< "forward references to 'enum' types are a Microsoft extension">, InGroup; def ext_forward_ref_enum_def : Extension< "redeclaration of already-defined enum %0 is a GNU extension">, InGroup; def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; def err_duplicate_member : Error<"duplicate member %0">; def err_misplaced_ivar : Error< "instance variables may not be placed in %select{categories|class extension}0">; def warn_ivars_in_interface : Warning< "declaration of instance variables in the interface is deprecated">, InGroup>, DefaultIgnore; def ext_enum_value_not_int : Extension< "ISO C restricts enumerator values to range of 'int' (%0 is too " "%select{small|large}1)">; def ext_enum_too_large : ExtWarn< "enumeration values exceed range of largest integer">, InGroup; def ext_enumerator_increment_too_large : ExtWarn< "incremented enumerator value %0 is not representable in the " "largest integer type">, InGroup; def warn_illegal_constant_array_size : Extension< "size of static array must be an integer constant expression">; def err_vm_decl_in_file_scope : Error< "variably modified type declaration not allowed at file scope">; def err_vm_decl_has_extern_linkage : Error< "variably modified type declaration cannot have 'extern' linkage">; def err_typecheck_field_variable_size : Error< "fields must have a constant size: 'variable length array in structure' " "extension will never be supported">; def err_vm_func_decl : Error< "function declaration cannot have variably modified type">; def err_array_too_large : Error< "array is too large (%0 elements)">; def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" InGroup; // -Wpadded, -Wpacked def warn_padded_struct_field : Warning< "padding %select{struct|interface|class}0 %1 with %2 " "%select{byte|bit}3%select{|s}4 to align %5">, InGroup, DefaultIgnore; def warn_padded_struct_anon_field : Warning< "padding %select{struct|interface|class}0 %1 with %2 " "%select{byte|bit}3%select{|s}4 to align anonymous bit-field">, InGroup, DefaultIgnore; def warn_padded_struct_size : Warning< "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 " "to alignment boundary">, InGroup, DefaultIgnore; def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup, DefaultIgnore; def err_typecheck_negative_array_size : Error<"array size is negative">; def warn_typecheck_negative_array_new_size : Warning<"array size is negative">, // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" InGroup; def warn_typecheck_function_qualifiers : Warning< "qualifier on function type %0 has unspecified behavior">; def warn_typecheck_reference_qualifiers : Warning< "'%0' qualifier on reference type %1 has no effect">, InGroup; def err_typecheck_invalid_restrict_not_pointer : Error< "restrict requires a pointer or reference (%0 is invalid)">; def err_typecheck_invalid_restrict_not_pointer_noarg : Error< "restrict requires a pointer or reference">; def err_typecheck_invalid_restrict_invalid_pointee : Error< "pointer to function type %0 may not be 'restrict' qualified">; def ext_typecheck_zero_array_size : Extension< "zero size arrays are an extension">, InGroup; def err_typecheck_zero_array_size : Error< "zero-length arrays are not permitted in C++">; def warn_typecheck_zero_static_array_size : Warning< "'static' has no effect on zero-length arrays">, InGroup; def err_array_size_non_int : Error<"size of array has non-integer type %0">; def err_init_element_not_constant : Error< "initializer element is not a compile-time constant">; def ext_aggregate_init_not_constant : Extension< "initializer for aggregate is not a compile-time constant">, InGroup; def err_local_cant_init : Error< "'__local' variable cannot have an initializer">; def err_block_extern_cant_init : Error< "'extern' variable cannot have an initializer">; def warn_extern_init : Warning<"'extern' variable has an initializer">, InGroup>; def err_variable_object_no_init : Error< "variable-sized object may not be initialized">; def err_excess_initializers : Error< "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; def ext_excess_initializers : ExtWarn< "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; def err_excess_initializers_in_char_array_initializer : Error< "excess elements in char array initializer">; def ext_excess_initializers_in_char_array_initializer : ExtWarn< "excess elements in char array initializer">; def err_initializer_string_for_char_array_too_long : Error< "initializer-string for char array is too long">; def ext_initializer_string_for_char_array_too_long : ExtWarn< "initializer-string for char array is too long">; def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; def warn_braces_around_scalar_init : Warning< "braces around scalar initializer">; def ext_many_braces_around_scalar_init : ExtWarn< "too many braces around scalar initializer">; def ext_complex_component_init : Extension< "complex initialization specifying real and imaginary components " "is an extension">, InGroup>; def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; def warn_cxx98_compat_empty_scalar_initializer : Warning< "scalar initialized from empty initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_reference_list_init : Warning< "reference initialized from initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_initializer_list_init : Warning< "initialization of initializer_list object is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_ctor_list_init : Warning< "constructor call from initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def err_illegal_initializer : Error< "illegal initializer (only variables can be initialized)">; def err_illegal_initializer_type : Error<"illegal initializer type %0">; def ext_init_list_type_narrowing : ExtWarn< "type %0 cannot be narrowed to %1 in initializer list">, InGroup, DefaultError, SFINAEFailure; def ext_init_list_variable_narrowing : ExtWarn< "non-constant-expression cannot be narrowed from type %0 to %1 in " "initializer list">, InGroup, DefaultError, SFINAEFailure; def ext_init_list_constant_narrowing : ExtWarn< "constant expression evaluates to %0 which cannot be narrowed to type %1">, InGroup, DefaultError, SFINAEFailure; def warn_init_list_type_narrowing : Warning< "type %0 cannot be narrowed to %1 in initializer list in C++11">, InGroup, DefaultIgnore; def warn_init_list_variable_narrowing : Warning< "non-constant-expression cannot be narrowed from type %0 to %1 in " "initializer list in C++11">, InGroup, DefaultIgnore; def warn_init_list_constant_narrowing : Warning< "constant expression evaluates to %0 which cannot be narrowed to type %1 in " "C++11">, InGroup, DefaultIgnore; def note_init_list_narrowing_silence : Note< "insert an explicit cast to silence this issue">; def err_init_objc_class : Error< "cannot initialize Objective-C class type %0">; def err_implicit_empty_initializer : Error< "initializer for aggregate with no elements requires explicit braces">; def err_bitfield_has_negative_width : Error< "bit-field %0 has negative width (%1)">; def err_anon_bitfield_has_negative_width : Error< "anonymous bit-field has negative width (%0)">; def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; def err_bitfield_width_exceeds_type_size : Error< "size of bit-field %0 (%1 bits) exceeds size of its type (%2 bits)">; def err_anon_bitfield_width_exceeds_type_size : Error< "size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">; def err_incorrect_number_of_vector_initializers : Error< "number of elements must be either one or match the size of the vector">; // Used by C++ which allows bit-fields that are wider than the type. def warn_bitfield_width_exceeds_type_size: Warning< "size of bit-field %0 (%1 bits) exceeds the size of its type; value will be " "truncated to %2 bits">; def warn_anon_bitfield_width_exceeds_type_size : Warning< "size of anonymous bit-field (%0 bits) exceeds size of its type; value will " "be truncated to %1 bits">; def warn_missing_braces : Warning< "suggest braces around initialization of subobject">, InGroup, DefaultIgnore; def err_redefinition_of_label : Error<"redefinition of label %0">; def err_undeclared_label_use : Error<"use of undeclared label %0">; def err_goto_ms_asm_label : Error< "cannot jump from this goto statement to label %0 inside an inline assembly block">; def note_goto_ms_asm_label : Note< "inline assembly label %0 declared here">; def warn_unused_label : Warning<"unused label %0">, InGroup, DefaultIgnore; def err_goto_into_protected_scope : Error< "cannot jump from this goto statement to its label">; def ext_goto_into_protected_scope : ExtWarn< "jump from this goto statement to its label is a Microsoft extension">, InGroup; def warn_cxx98_compat_goto_into_protected_scope : Warning< "jump from this goto statement to its label is incompatible with C++98">, InGroup, DefaultIgnore; def err_switch_into_protected_scope : Error< "cannot jump from switch statement to this case label">; def warn_cxx98_compat_switch_into_protected_scope : Warning< "jump from switch statement to this case label is incompatible with C++98">, InGroup, DefaultIgnore; def err_indirect_goto_without_addrlabel : Error< "indirect goto in function with no address-of-label expressions">; def err_indirect_goto_in_protected_scope : Error< "cannot jump from this indirect goto statement to one of its possible targets">; def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning< "jump from this indirect goto statement to one of its possible targets " "is incompatible with C++98">, InGroup, DefaultIgnore; def note_indirect_goto_target : Note< "possible target of indirect goto statement">; def note_protected_by_variable_init : Note< "jump bypasses variable initialization">; def note_protected_by_variable_nontriv_destructor : Note< "jump bypasses variable with a non-trivial destructor">; def note_protected_by_variable_non_pod : Note< "jump bypasses initialization of non-POD variable">; def note_protected_by_cleanup : Note< "jump bypasses initialization of variable with __attribute__((cleanup))">; def note_protected_by_vla_typedef : Note< "jump bypasses initialization of VLA typedef">; def note_protected_by_vla_type_alias : Note< "jump bypasses initialization of VLA type alias">; def note_protected_by_vla : Note< "jump bypasses initialization of variable length array">; def note_protected_by_objc_try : Note< "jump bypasses initialization of @try block">; def note_protected_by_objc_catch : Note< "jump bypasses initialization of @catch block">; def note_protected_by_objc_finally : Note< "jump bypasses initialization of @finally block">; def note_protected_by_objc_synchronized : Note< "jump bypasses initialization of @synchronized block">; def note_protected_by_objc_autoreleasepool : Note< "jump bypasses auto release push of @autoreleasepool block">; def note_protected_by_cxx_try : Note< "jump bypasses initialization of try block">; def note_protected_by_cxx_catch : Note< "jump bypasses initialization of catch block">; def note_protected_by___block : Note< "jump bypasses setup of __block variable">; def note_protected_by_objc_ownership : Note< "jump bypasses initialization of retaining variable">; def note_enters_block_captures_cxx_obj : Note< "jump enters lifetime of block which captures a destructible C++ object">; def note_enters_block_captures_strong : Note< "jump enters lifetime of block which strongly captures a variable">; def note_enters_block_captures_weak : Note< "jump enters lifetime of block which weakly captures a variable">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; def note_exits_dtor : Note< "jump exits scope of variable with non-trivial destructor">; def note_exits_temporary_dtor : Note< "jump exits scope of lifetime-extended temporary with non-trivial " "destructor">; def note_exits___block : Note< "jump exits scope of __block variable">; def note_exits_objc_try : Note< "jump exits @try block">; def note_exits_objc_catch : Note< "jump exits @catch block">; def note_exits_objc_finally : Note< "jump exits @finally block">; def note_exits_objc_synchronized : Note< "jump exits @synchronized block">; def note_exits_cxx_try : Note< "jump exits try block">; def note_exits_cxx_catch : Note< "jump exits catch block">; def note_exits_objc_autoreleasepool : Note< "jump exits autoreleasepool block">; def note_exits_objc_ownership : Note< "jump exits scope of retaining variable">; def note_exits_block_captures_cxx_obj : Note< "jump exits lifetime of block which captures a destructible C++ object">; def note_exits_block_captures_strong : Note< "jump exits lifetime of block which strongly captures a variable">; def note_exits_block_captures_weak : Note< "jump exits lifetime of block which weakly captures a variable">; def err_func_returning_array_function : Error< "function cannot return %select{array|function}0 type %1">; def err_field_declared_as_function : Error<"field %0 declared as a function">; def err_field_incomplete : Error<"field has incomplete type %0">; def ext_variable_sized_type_in_struct : ExtWarn< "field %0 with variable sized type %1 not at the end of a struct or class is" " a GNU extension">, InGroup; def ext_c99_flexible_array_member : Extension< "flexible array members are a C99 feature">, InGroup; def err_flexible_array_virtual_base : Error< "flexible array member %0 not allowed in " "%select{struct|interface|union|class|enum}1 which has a virtual base class">; def err_flexible_array_empty_aggregate : Error< "flexible array member %0 not allowed in otherwise empty " "%select{struct|interface|union|class|enum}1">; def err_flexible_array_has_nontrivial_dtor : Error< "flexible array member %0 of type %1 with non-trivial destruction">; def ext_flexible_array_in_struct : Extension< "%0 may not be nested in a struct due to flexible array member">, InGroup; def ext_flexible_array_in_array : Extension< "%0 may not be used as an array element due to flexible array member">, InGroup; def err_flexible_array_init : Error< "initialization of flexible array member is not allowed">; def ext_flexible_array_empty_aggregate_ms : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, InGroup; def err_flexible_array_union : Error< "flexible array member %0 in a union is not allowed">; def ext_flexible_array_union_ms : Extension< "flexible array member %0 in a union is a Microsoft extension">, InGroup; def ext_flexible_array_empty_aggregate_gnu : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a GNU extension">, InGroup; def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup; let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. let CategoryName = "ARC Weak References" in { def err_arc_weak_no_runtime : Error< "the current deployment target does not support automated __weak references">; def err_arc_unsupported_weak_class : Error< "class is incompatible with __weak references">; def err_arc_weak_unavailable_assign : Error< "assignment of a weak-unavailable object to a __weak object">; def err_arc_weak_unavailable_property : Error< "synthesizing __weak instance variable of type %0, which does not " "support weak references">; def note_implemented_by_class : Note< "when implemented by class %0">; def err_arc_convesion_of_weak_unavailable : Error< "%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to" " a __weak object of type %2">; } // end "ARC Weak References" category let CategoryName = "ARC Restrictions" in { def err_arc_illegal_explicit_message : Error< "ARC forbids explicit message send of %0">; def err_arc_unused_init_message : Error< "the result of a delegate init call must be immediately returned " "or assigned to 'self'">; def err_arc_mismatched_cast : Error< "%select{implicit conversion|cast}0 of " "%select{%2|a non-Objective-C pointer type %2|a block pointer|" "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1" " to %3 is disallowed with ARC">; def err_arc_nolifetime_behavior : Error< "explicit ownership qualifier on cast result has no effect">; def err_arc_objc_object_in_tag : Error< "ARC forbids %select{Objective-C objects|blocks}0 in " "%select{struct|interface|union|<>|enum}1">; def err_arc_objc_property_default_assign_on_object : Error< "ARC forbids synthesizing a property of an Objective-C object " "with unspecified ownership or storage attribute">; def err_arc_illegal_selector : Error< "ARC forbids use of %0 in a @selector">; def err_arc_illegal_method_def : Error< "ARC forbids %select{implementation|synthesis}0 of %1">; def warn_arc_strong_pointer_objc_pointer : Warning< "method parameter of type %0 with no explicit ownership">, InGroup>, DefaultIgnore; } // end "ARC Restrictions" category def err_arc_lost_method_convention : Error< "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " "method, but its implementation doesn't match because %select{" "its result type is not an object pointer|" "its result type is unrelated to its receiver type}1">; def note_arc_lost_method_convention : Note<"declaration in interface">; def err_arc_gained_method_convention : Error< "method implementation does not match its declaration">; def note_arc_gained_method_convention : Note< "declaration in interface is not in the '%select{alloc|copy|init|new}0' " "family because %select{its result type is not an object pointer|" "its result type is unrelated to its receiver type}1">; def err_typecheck_arc_assign_self : Error< "cannot assign to 'self' outside of a method in the init family">; def err_typecheck_arc_assign_self_class_method : Error< "cannot assign to 'self' in a class method">; def err_typecheck_arr_assign_enumeration : Error< "fast enumeration variables can't be modified in ARC by default; " "declare the variable __strong to allow this">; def warn_arc_retained_assign : Warning< "assigning retained object to %select{weak|unsafe_unretained}0 " "%select{property|variable}1" "; object will be released after assignment">, InGroup; def warn_arc_retained_property_assign : Warning< "assigning retained object to unsafe property" "; object will be released after assignment">, InGroup; def warn_arc_literal_assign : Warning< "assigning %select{array literal|dictionary literal|numeric literal|boxed expression||block literal}0" " to a weak %select{property|variable}1" "; object will be released after assignment">, InGroup; def err_arc_new_array_without_ownership : Error< "'new' cannot allocate an array of %0 with no explicit ownership">; def err_arc_autoreleasing_var : Error< "%select{__block variables|global variables|fields|instance variables}0 cannot have " "__autoreleasing ownership">; def err_arc_autoreleasing_capture : Error< "cannot capture __autoreleasing variable in a " "%select{block|lambda by copy}0">; def err_arc_thread_ownership : Error< "thread-local variable has non-trivial ownership: type is %0">; def err_arc_indirect_no_ownership : Error< "%select{pointer|reference}1 to non-const type %0 with no explicit ownership">; def err_arc_array_param_no_ownership : Error< "must explicitly describe intended ownership of an object array parameter">; def err_arc_pseudo_dtor_inconstant_quals : Error< "pseudo-destructor destroys object of type %0 with inconsistently-qualified " "type %1">; def err_arc_init_method_unrelated_result_type : Error< "init methods must return a type related to the receiver type">; def err_arc_nonlocal_writeback : Error< "passing address of %select{non-local|non-scalar}0 object to " "__autoreleasing parameter for write-back">; def err_arc_method_not_found : Error< "no known %select{instance|class}1 method for selector %0">; def err_arc_receiver_forward_class : Error< "receiver %0 for class message is a forward declaration">; def err_arc_may_not_respond : Error< "no visible @interface for %0 declares the selector %1">; def err_arc_receiver_forward_instance : Error< "receiver type %0 for instance message is a forward declaration">; def warn_receiver_forward_instance : Warning< "receiver type %0 for instance message is a forward declaration">, InGroup, DefaultIgnore; def err_arc_collection_forward : Error< "collection expression type %0 is a forward declaration">; def err_arc_multiple_method_decl : Error< "multiple methods named %0 found with mismatched result, " "parameter type or attributes">; def warn_arc_lifetime_result_type : Warning< "ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 " "lifetime qualifier on return type is ignored">, InGroup; let CategoryName = "ARC Retain Cycle" in { def warn_arc_retain_cycle : Warning< "capturing %0 strongly in this block is likely to lead to a retain cycle">, InGroup; def note_arc_retain_cycle_owner : Note< "block will be retained by %select{the captured object|an object strongly " "retained by the captured object}0">; } // end "ARC Retain Cycle" category def warn_arc_object_memaccess : Warning< "%select{destination for|source of}0 this %1 call is a pointer to " "ownership-qualified type %2">, InGroup; let CategoryName = "ARC and @properties" in { def err_arc_strong_property_ownership : Error< "existing instance variable %1 for strong property %0 may not be " "%select{|__unsafe_unretained||__weak}2">; def err_arc_assign_property_ownership : Error< "existing instance variable %1 for property %0 with %select{unsafe_unretained| assign}2 " "attribute must be __unsafe_unretained">; def err_arc_inconsistent_property_ownership : Error< "%select{|unsafe_unretained|strong|weak}1 property %0 may not also be " "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">; } // end "ARC and @properties" category def err_arc_atomic_ownership : Error< "cannot perform atomic operation on a pointer to type %0: type has " "non-trivial ownership">; let CategoryName = "ARC Casting Rules" in { def err_arc_bridge_cast_incompatible : Error< "incompatible types casting %0 to %1 with a %select{__bridge|" "__bridge_transfer|__bridge_retained}2 cast">; def err_arc_bridge_cast_wrong_kind : Error< "cast of %select{Objective-C|block|C}0 pointer type %1 to " "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" "__bridge_transfer|__bridge_retained}4">; def err_arc_cast_requires_bridge : Error< "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 " "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 " "requires a bridged cast">; def note_arc_bridge : Note< "use __bridge to convert directly (no change in ownership)">; def note_arc_cstyle_bridge : Note< "use __bridge with C-style cast to convert directly (no change in ownership)">; def note_arc_bridge_transfer : Note< "use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer " "ownership of a +1 %0 into ARC">; def note_arc_cstyle_bridge_transfer : Note< "use __bridge_transfer with C-style cast to transfer " "ownership of a +1 %0 into ARC">; def note_arc_bridge_retained : Note< "use %select{__bridge_retained|CFBridgingRetain call}1 to make an " "ARC object available as a +1 %0">; def note_arc_cstyle_bridge_retained : Note< "use __bridge_retained with C-style cast to make an " "ARC object available as a +1 %0">; } // ARC Casting category } // ARC category name def err_flexible_array_init_needs_braces : Error< "flexible array requires brace-enclosed initializer">; def err_illegal_decl_array_of_functions : Error< "'%0' declared as array of functions of type %1">; def err_illegal_decl_array_incomplete_type : Error< "array has incomplete element type %0">; def err_illegal_message_expr_incomplete_type : Error< "Objective-C message has incomplete result type %0">; def err_illegal_decl_array_of_references : Error< "'%0' declared as array of references of type %1">; def err_decl_negative_array_size : Error< "'%0' declared as an array with a negative size">; def err_array_static_outside_prototype : Error< "%0 used in array declarator outside of function prototype">; def err_array_static_not_outermost : Error< "%0 used in non-outermost array type derivation">; def err_array_star_outside_prototype : Error< "star modifier used outside of function prototype">; def err_illegal_decl_pointer_to_reference : Error< "'%0' declared as a pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_reference : Error< "'%0' declared as a member pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_void : Error< "'%0' declared as a member pointer to void">; def err_illegal_decl_mempointer_in_nonclass : Error< "'%0' does not point into a class">; def err_mempointer_in_nonclass_type : Error< "member pointer refers into non-class type %0">; def err_reference_to_void : Error<"cannot form a reference to 'void'">; def err_nonfunction_block_type : Error< "block pointer to non-function type is invalid">; def err_return_block_has_expr : Error<"void block should not return a value">; def err_block_return_missing_expr : Error< "non-void block should return a value">; def err_func_def_incomplete_result : Error< "incomplete result type %0 in function definition">; def err_atomic_specifier_bad_type : Error< "_Atomic cannot be applied to " "%select{incomplete |array |function |reference |atomic |qualified |}0type " "%1 %select{||||||which is not trivially copyable}0">; // Expressions. def ext_sizeof_alignof_function_type : Extension< "invalid application of '%select{sizeof|alignof|vec_step}0' to a " "function type">, InGroup; def ext_sizeof_alignof_void_type : Extension< "invalid application of '%select{sizeof|alignof|vec_step}0' to a void " "type">, InGroup; def err_opencl_sizeof_alignof_type : Error< "invalid application of '%select{sizeof|alignof|vec_step}0' to a void type">; def err_sizeof_alignof_incomplete_type : Error< "invalid application of '%select{sizeof|alignof|vec_step}0' to an " "incomplete type %1">; def err_sizeof_alignof_function_type : Error< "invalid application of '%select{sizeof|alignof|vec_step}0' to a " "function type">; def err_sizeof_alignof_bitfield : Error< "invalid application of '%select{sizeof|alignof}0' to bit-field">; def err_alignof_member_of_incomplete_type : Error< "invalid application of 'alignof' to a field of a class still being defined">; def err_vecstep_non_scalar_vector_type : Error< "'vec_step' requires built-in scalar or vector type, %0 invalid">; def err_offsetof_incomplete_type : Error< "offsetof of incomplete type %0">; def err_offsetof_record_type : Error< "offsetof requires struct, union, or class type, %0 invalid">; def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; def ext_offsetof_extended_field_designator : Extension< "using extended field designator is an extension">, InGroup>; def ext_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, InGroup; def ext_offsetof_non_standardlayout_type : ExtWarn< "offset of on non-standard-layout type %0">, InGroup; def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">; def err_offsetof_field_of_virtual_base : Error< "invalid application of 'offsetof' to a field of a virtual base">; def warn_sub_ptr_zero_size_types : Warning< "subtraction of pointers to type %0 of zero size has undefined behavior">, InGroup; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, InGroup>, DefaultIgnore; def warn_division_by_zero : Warning<"division by zero is undefined">, InGroup; def warn_remainder_by_zero : Warning<"remainder by zero is undefined">, InGroup; def warn_shift_negative : Warning<"shift count is negative">, InGroup>; def warn_shift_gt_typewidth : Warning<"shift count >= width of type">, InGroup>; def warn_shift_result_gt_typewidth : Warning< "signed shift result (%0) requires %1 bits to represent, but %2 only has " "%3 bits">, InGroup>; def warn_shift_result_sets_sign_bit : Warning< "signed shift result (%0) sets the sign bit of the shift expression's " "type (%1) and becomes negative">, InGroup>, DefaultIgnore; def warn_precedence_bitwise_rel : Warning< "%0 has lower precedence than %1; %1 will be evaluated first">, InGroup; def note_precedence_bitwise_first : Note< "place parentheses around the %0 expression to evaluate it first">; def note_precedence_silence : Note< "place parentheses around the '%0' expression to silence this warning">; def warn_precedence_conditional : Warning< "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">, InGroup; def note_precedence_conditional_first : Note< "place parentheses around the '?:' expression to evaluate it first">; def warn_logical_instead_of_bitwise : Warning< "use of logical '%0' with constant operand">, InGroup>; def note_logical_instead_of_bitwise_change_operator : Note< "use '%0' for a bitwise operation">; def note_logical_instead_of_bitwise_remove_constant : Note< "remove constant to silence this warning">; def warn_bitwise_and_in_bitwise_or : Warning< "'&' within '|'">, InGroup; def warn_logical_and_in_logical_or : Warning< "'&&' within '||'">, InGroup; def warn_overloaded_shift_in_comparison :Warning< "overloaded operator %select{>>|<<}0 has higher precedence than " "comparison operator">, InGroup; def note_evaluate_comparison_first :Note< "place parentheses around comparison expression to evaluate it first">; def warn_addition_in_bitshift : Warning< "operator '%0' has lower precedence than '%1'; " "'%1' will be evaluated first">, InGroup; def warn_self_assignment : Warning< "explicitly assigning value of variable of type %0 to itself">, InGroup, DefaultIgnore; def warn_self_move : Warning< "explicitly moving variable of type %0 to itself">, InGroup, DefaultIgnore; def warn_string_plus_int : Warning< "adding %0 to a string does not append to the string">, InGroup; def warn_string_plus_char : Warning< "adding %0 to a string pointer does not append to the string">, InGroup; def note_string_plus_scalar_silence : Note< "use array indexing to silence this warning">; def warn_sizeof_array_param : Warning< "sizeof on array function parameter will return size of %0 instead of %1">, InGroup; def warn_sizeof_array_decay : Warning< "sizeof on pointer operation will return size of %0 instead of %1">, InGroup; def err_sizeof_nonfragile_interface : Error< "application of '%select{alignof|sizeof}1' to interface %0 is " "not supported on this architecture and platform">; def err_atdef_nonfragile_interface : Error< "use of @defs is not supported on this architecture and platform">; def err_subscript_nonfragile_interface : Error< "subscript requires size of interface %0, which is not constant for " "this architecture and platform">; def err_arithmetic_nonfragile_interface : Error< "arithmetic on pointer to interface %0, which is not a constant size for " "this architecture and platform">; def ext_subscript_non_lvalue : Extension< "ISO C90 does not allow subscripting non-lvalue array">; def err_typecheck_subscript_value : Error< "subscripted value is not an array, pointer, or vector">; def err_typecheck_subscript_not_integer : Error< "array subscript is not an integer">; def err_subscript_function_type : Error< "subscript of pointer to function type %0">; def err_subscript_incomplete_type : Error< "subscript of pointer to incomplete type %0">; def err_dereference_incomplete_type : Error< "dereference of pointer to incomplete type %0">; def ext_gnu_subscript_void_type : Extension< "subscript of a pointer to void is a GNU extension">, InGroup; def err_typecheck_member_reference_struct_union : Error< "member reference base type %0 is not a structure or union">; def err_typecheck_member_reference_ivar : Error< "%0 does not have a member named %1">; def error_arc_weak_ivar_access : Error< "dereferencing a __weak pointer is not allowed due to possible " "null value caused by race condition, assign it to strong variable first">; def err_typecheck_member_reference_arrow : Error< "member reference type %0 is not a pointer">; def err_typecheck_member_reference_suggestion : Error< "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">; def note_typecheck_member_reference_suggestion : Note< "did you mean to use '.' instead?">; def note_member_reference_arrow_from_operator_arrow : Note< "'->' applied to return value of the operator->() declared here">; def err_typecheck_member_reference_type : Error< "cannot refer to type member %0 in %1 with '%select{.|->}2'">; def err_typecheck_member_reference_unknown : Error< "cannot refer to member %0 in %1 with '%select{.|->}2'">; def err_member_reference_needs_call : Error< "base of member reference is a function; perhaps you meant to call " "it%select{| with no arguments}0?">; def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, InGroup, DefaultIgnore; def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_no_member_overloaded_arrow : Error< "no member named %0 in %1; did you mean to use '->' instead of '.'?">; def err_member_not_yet_instantiated : Error< "no member %0 in %1; it has not yet been instantiated">; def note_non_instantiated_member_here : Note< "not-yet-instantiated member is declared here">; def err_enumerator_does_not_exist : Error< "enumerator %0 does not exist in instantiation of %1">; def note_enum_specialized_here : Note< "enum %0 was explicitly specialized here">; def err_member_redeclared : Error<"class member cannot be redeclared">; def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">, InGroup; def err_member_redeclared_in_instantiation : Error< "multiple overloads of %0 instantiate to the same signature %1">; def err_member_name_of_class : Error<"member %0 has the same name as its class">; def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_decl_does_not_match : Error< "out-of-line %select{declaration|definition}2 of %0 " "does not match any declaration in %1">; def err_friend_decl_with_def_arg_must_be_def : Error< "friend declaration specifying a default argument must be a definition">; def err_friend_decl_with_def_arg_redeclared : Error< "friend declaration specifying a default argument must be the only declaration">; def err_friend_decl_does_not_match : Error< "friend declaration of %0 does not match any declaration in %1">; def err_member_decl_does_not_match_suggest : Error< "out-of-line %select{declaration|definition}2 of %0 " "does not match any declaration in %1; did you mean %3?">; def err_member_def_does_not_match_ret_type : Error< "return type of out-of-line definition of %q0 differs from " "that in the declaration">; def err_nonstatic_member_out_of_line : Error< "non-static data member defined out-of-line">; def err_qualified_typedef_declarator : Error< "typedef declarator cannot be qualified">; def err_qualified_param_declarator : Error< "parameter declarator cannot be qualified">; def ext_out_of_line_declaration : ExtWarn< "out-of-line declaration of a member must be a definition">, InGroup, DefaultError; def warn_member_extra_qualification : Warning< "extra qualification on member %0">, InGroup; def err_member_extra_qualification : Error< "extra qualification on member %0">; def warn_namespace_member_extra_qualification : Warning< "extra qualification on member %0">, InGroup>; def err_member_qualification : Error< "non-friend class member %0 cannot have a qualified name">; def note_member_def_close_match : Note<"member declaration nearly matches">; def note_member_def_close_const_match : Note< "member declaration does not match because " "it %select{is|is not}0 const qualified">; def note_member_def_close_param_match : Note< "type of %ordinal0 parameter of member declaration does not match definition" "%diff{ ($ vs $)|}1,2">; def note_local_decl_close_match : Note<"local declaration nearly matches">; def note_local_decl_close_param_match : Note< "type of %ordinal0 parameter of local declaration does not match definition" "%diff{ ($ vs $)|}1,2">; def err_typecheck_ivar_variable_size : Error< "instance variables must have a constant size">; def err_ivar_reference_type : Error< "instance variables cannot be of reference type">; def err_typecheck_illegal_increment_decrement : Error< "cannot %select{decrement|increment}1 value of type %0">; def err_typecheck_arithmetic_incomplete_type : Error< "arithmetic on a pointer to an incomplete type %0">; def err_typecheck_pointer_arith_function_type : Error< "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 " "function type%select{|s}2 %1%select{| and %3}2">; def err_typecheck_pointer_arith_void_type : Error< "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; def err_typecheck_decl_incomplete_type : Error< "variable has incomplete type %0">; def err_typecheck_decl_incomplete_type___float128 : Error< "support for type '__float128' is not yet implemented">; def ext_typecheck_decl_incomplete_type : ExtWarn< "tentative definition of variable with internal linkage has incomplete non-array type %0">, InGroup>; def err_tentative_def_incomplete_type : Error< "tentative definition has type %0 that is never completed">; def warn_tentative_incomplete_array : Warning< "tentative array definition assumed to have one element">; def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; def err_array_init_not_init_list : Error< "array initializer must be an initializer " "list%select{| or string literal| or wide string literal}0">; def err_array_init_narrow_string_into_wchar : Error< "initializing wide char array with non-wide string literal">; def err_array_init_wide_string_into_char : Error< "initializing char array with wide string literal">; def err_array_init_incompat_wide_string_into_wchar : Error< "initializing wide char array with incompatible wide string literal">; def err_array_init_different_type : Error< "cannot initialize array %diff{of type $ with array of type $|" "with different type of array}0,1">; def err_array_init_non_constant_array : Error< "cannot initialize array %diff{of type $ with non-constant array of type $|" "with different type of array}0,1">; def ext_array_init_copy : Extension< "initialization of an array " "%diff{of type $ from a compound literal of type $|" "from a compound literal}0,1 is a GNU extension">, InGroup; // This is intentionally not disabled by -Wno-gnu. def ext_array_init_parens : ExtWarn< "parenthesized initialization of a member array is a GNU extension">, InGroup>, DefaultError; def warn_deprecated_string_literal_conversion : Warning< "conversion from string literal to %0 is deprecated">, InGroup; def ext_deprecated_string_literal_conversion : ExtWarn< "ISO C++11 does not allow conversion from string literal to %0">, InGroup, SFINAEFailure; def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; def err_typecheck_sclass_fscope : Error< "illegal storage class on file-scoped variable">; def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">, InGroup; def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration " "of a type">, InGroup; def err_standalone_class_nested_name_specifier : Error< "forward declaration of %select{class|struct|interface|union|enum}0 cannot " "have a nested name specifier">; def err_typecheck_sclass_func : Error<"illegal storage class on function">; def err_static_block_func : Error< "function declared in block scope cannot have 'static' storage class">; def err_typecheck_address_of : Error<"address of %select{bit-field" "|vector element|property expression|register variable}0 requested">; def ext_typecheck_addrof_void : Extension< "ISO C forbids taking the address of an expression of type 'void'">; def err_unqualified_pointer_member_function : Error< "must explicitly qualify name of member function when taking its address">; def err_invalid_form_pointer_member_function : Error< "cannot create a non-constant pointer to member function">; def err_parens_pointer_member_function : Error< "cannot parenthesize the name of a method when forming a member pointer">; def err_typecheck_invalid_lvalue_addrof_addrof_function : Error< "extra '&' taking address of overloaded function">; def err_typecheck_invalid_lvalue_addrof : Error< "cannot take the address of an rvalue of type %0">; def ext_typecheck_addrof_temporary : ExtWarn< "taking the address of a temporary object of type %0">, InGroup>, DefaultError; def err_typecheck_addrof_temporary : Error< "taking the address of a temporary object of type %0">; def err_typecheck_addrof_dtor : Error< "taking the address of a destructor">; def err_typecheck_unary_expr : Error< "invalid argument type %0 to unary expression">; def err_typecheck_indirection_requires_pointer : Error< "indirection requires pointer operand (%0 invalid)">; def ext_typecheck_indirection_through_void_pointer : Extension< "ISO C++ does not allow indirection on operand of type %0">, InGroup>; def warn_indirection_through_null : Warning< "indirection of non-volatile null pointer will be deleted, not trap">, InGroup; def note_indirection_through_null : Note< "consider using __builtin_trap() or qualifying pointer with 'volatile'">; def warn_pointer_indirection_from_incompatible_type : Warning< "dereference of type %1 that was reinterpret_cast from type %0 has undefined " "behavior">, InGroup, DefaultIgnore; def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">; def err_typecheck_sub_ptr_compatible : Error< "%diff{$ and $ are not pointers to compatible types|" "pointers to incompatible types}0,1">; def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn< "ordered comparison between pointer and integer (%0 and %1)">; def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< "ordered comparison between pointer and zero (%0 and %1) is an extension">; def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< "ordered comparison of function pointers (%0 and %1)">; def ext_typecheck_comparison_of_fptr_to_void : Extension< "equality comparison between function pointer and void pointer (%0 and %1)">; def err_typecheck_comparison_of_fptr_to_void : Error< "equality comparison between function pointer and void pointer (%0 and %1)">; def ext_typecheck_comparison_of_pointer_integer : ExtWarn< "comparison between pointer and integer (%0 and %1)">; def err_typecheck_comparison_of_pointer_integer : Error< "comparison between pointer and integer (%0 and %1)">; def ext_typecheck_comparison_of_distinct_pointers : ExtWarn< "comparison of distinct pointer types%diff{ ($ and $)|}0,1">, InGroup; def ext_typecheck_cond_incompatible_operands : ExtWarn< "incompatible operand types (%0 and %1)">; def err_cond_voidptr_arc : Error < "operands to conditional of types%diff{ $ and $|}0,1 are incompatible " "in ARC mode">; def err_typecheck_comparison_of_distinct_pointers : Error< "comparison of distinct pointer types%diff{ ($ and $)|}0,1">; def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn< "comparison of distinct pointer types (%0 and %1) uses non-standard " "composite pointer type %2">, InGroup; def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error< "%select{comparison between %diff{ ($ and $)|}0,1" "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1}2" " which are pointers to non-overlapping address spaces">; def err_typecheck_assign_const : Error<"read-only variable is not assignable">; def warn_mixed_sign_comparison : Warning< "comparison of integers of different signs: %0 and %1">, InGroup, DefaultIgnore; def warn_lunsigned_always_true_comparison : Warning< "comparison of unsigned%select{| enum}2 expression %0 is always %1">, InGroup; def warn_out_of_range_compare : Warning< "comparison of %select{constant %0|true|false}1 with " "%select{expression of type %2|boolean expression}3 is always " "%select{false|true}4">, InGroup; def warn_runsigned_always_true_comparison : Warning< "comparison of %0 unsigned%select{| enum}2 expression is always %1">, InGroup; def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types" "%diff{ ($ and $)|}0,1">, InGroup>; def warn_null_in_arithmetic_operation : Warning< "use of NULL in arithmetic operation">, InGroup; def warn_null_in_comparison_operation : Warning< "comparison between NULL and non-pointer " "%select{(%1 and NULL)|(NULL and %1)}0">, InGroup; def warn_logical_not_on_lhs_of_comparison : Warning< "logical not is only applied to the left hand side of this comparison">, InGroup; def note_logical_not_fix : Note< "add parentheses after the '!' to evaluate the comparison first">; def note_logical_not_silence_with_parens : Note< "add parentheses around left hand side expression to silence this warning">; def err_invalid_this_use : Error< "invalid use of 'this' outside of a non-static member function">; def err_this_static_member_func : Error< "'this' cannot be%select{| implicitly}0 used in a static member function " "declaration">; def err_invalid_member_use_in_static_method : Error< "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< "%select{static |non-}0member function %select{of type %2 |}1" "cannot have '%3' qualifier">; def err_compound_qualified_function_type : Error< "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1" "cannot have '%3' qualifier">; def err_ref_qualifier_overload : Error< "cannot overload a member function %select{without a ref-qualifier|with " "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; def err_invalid_non_static_member_use : Error< "invalid use of non-static data member %0">; def err_nested_non_static_member_use : Error< "%select{call to non-static member function|use of non-static data member}0 " "%2 of %1 from nested type %3">; def warn_cxx98_compat_non_static_member_use : Warning< "use of non-static data member %0 in an unevaluated context is " "incompatible with C++98">, InGroup, DefaultIgnore; def err_invalid_incomplete_type_use : Error< "invalid use of incomplete type %0">; def err_builtin_func_cast_more_than_one_arg : Error< "function-style cast to a builtin type can only take one argument">; def err_value_init_for_array_type : Error< "array types cannot be value-initialized">; def warn_format_nonliteral_noargs : Warning< "format string is not a string literal (potentially insecure)">, InGroup; def warn_format_nonliteral : Warning< "format string is not a string literal">, InGroup, DefaultIgnore; def err_unexpected_interface : Error< "unexpected interface name %0: expected expression">; def err_ref_non_value : Error<"%0 does not refer to a value">; def err_ref_vm_type : Error< "cannot refer to declaration with a variably modified type inside block">; def err_ref_flexarray_type : Error< "cannot refer to declaration of structure variable with flexible array member " "inside block">; def err_ref_array_type : Error< "cannot refer to declaration with an array type inside block">; def err_property_not_found : Error< "property %0 not found on object of type %1">; def err_invalid_property_name : Error< "%0 is not a valid property name (accessing an object of type %1)">; def err_getter_not_found : Error< "no getter method for read from property">; def err_objc_subscript_method_not_found : Error< "expected method to %select{read|write}1 %select{dictionary|array}2 element not " "found on object of type %0">; def err_objc_subscript_index_type : Error< "method index parameter type %0 is not integral type">; def err_objc_subscript_key_type : Error< "method key parameter type %0 is not object type">; def err_objc_subscript_dic_object_type : Error< "method object parameter type %0 is not object type">; def err_objc_subscript_object_type : Error< "cannot assign to this %select{dictionary|array}1 because assigning method's " "2nd parameter of type %0 is not an Objective-C pointer type">; def err_objc_subscript_base_type : Error< "%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">; def err_objc_multiple_subscript_type_conversion : Error< "indexing expression is invalid because subscript type %0 has " "multiple type conversion functions">; def err_objc_subscript_type_conversion : Error< "indexing expression is invalid because subscript type %0 is not an integral" " or Objective-C pointer type">; def err_objc_subscript_pointer : Error< "indexing expression is invalid because subscript type %0 is not an" " Objective-C pointer">; def err_objc_indexing_method_result_type : Error< "method for accessing %select{dictionary|array}1 element must have Objective-C" " object return type instead of %0">; def err_objc_index_incomplete_class_type : Error< "Objective-C index expression has incomplete class type %0">; def err_illegal_container_subscripting_op : Error< "illegal operation on Objective-C container subscripting">; def err_property_not_found_forward_class : Error< "property %0 cannot be found in forward class object %1">; def err_property_not_as_forward_class : Error< "property %0 refers to an incomplete Objective-C class %1 " "(with no @interface available)">; def note_forward_class : Note< "forward declaration of class here">; def err_duplicate_property : Error< "property has a previous declaration">; def ext_gnu_void_ptr : Extension< "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">, InGroup; def ext_gnu_ptr_func_arith : Extension< "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, InGroup; def error_readonly_message_assignment : Error< "assigning to 'readonly' return result of an Objective-C message not allowed">; def ext_integer_increment_complex : Extension< "ISO C does not support '++'/'--' on complex integer type %0">; def ext_integer_complement_complex : Extension< "ISO C does not support '~' for complex conjugation of %0">; def err_nosetter_property_assignment : Error< "%select{assignment to readonly property|" "no setter method %1 for assignment to property}0">; def err_nosetter_property_incdec : Error< "%select{%select{increment|decrement}1 of readonly property|" "no setter method %2 for %select{increment|decrement}1 of property}0">; def err_nogetter_property_compound_assignment : Error< "a getter method is needed to perform a compound assignment on a property">; def err_nogetter_property_incdec : Error< "no getter method %1 for %select{increment|decrement}0 of property">; def error_no_subobject_property_setting : Error< "expression is not assignable">; def err_qualified_objc_access : Error< "%select{property|instance variable}0 access cannot be qualified with '%1'">; def ext_freestanding_complex : Extension< "complex numbers are an extension in a freestanding C99 implementation">; // FIXME: Remove when we support imaginary. def err_imaginary_not_supported : Error<"imaginary types are not supported">; // Obj-c expressions def warn_root_inst_method_not_found : Warning< "instance method %0 is being used on 'Class' which is not in the root class">, InGroup; def warn_class_method_not_found : Warning< "class method %objcclass0 not found (return type defaults to 'id')">, InGroup; def warn_instance_method_on_class_found : Warning< "instance method %0 found instead of class method %1">, InGroup; def warn_inst_method_not_found : Warning< "instance method %objcinstance0 not found (return type defaults to 'id')">, InGroup; def warn_instance_method_not_found_with_typo : Warning< "instance method %objcinstance0 not found (return type defaults to 'id')" "; did you mean %objcinstance2?">, InGroup; def warn_class_method_not_found_with_typo : Warning< "class method %objcclass0 not found (return type defaults to 'id')" "; did you mean %objcclass2?">, InGroup; def error_method_not_found_with_typo : Error< "%select{instance|class}1 method %0 not found " "; did you mean %2?">; def error_no_super_class_message : Error< "no @interface declaration found in class messaging of %0">; def error_root_class_cannot_use_super : Error< "%0 cannot use 'super' because it is a root class">; def err_invalid_receiver_to_message_super : Error< "'super' is only valid in a method body">; def err_invalid_receiver_class_message : Error< "receiver type %0 is not an Objective-C class">; def err_missing_open_square_message_send : Error< "missing '[' at start of message send expression">; def warn_bad_receiver_type : Warning< "receiver type %0 is not 'id' or interface pointer, consider " "casting it to 'id'">,InGroup; def err_bad_receiver_type : Error<"bad receiver type %0">; def err_incomplete_receiver_type : Error<"incomplete receiver type %0">; def err_unknown_receiver_suggest : Error< "unknown receiver %0; did you mean %1?">; def error_objc_throw_expects_object : Error< "@throw requires an Objective-C object type (%0 invalid)">; def error_objc_synchronized_expects_object : Error< "@synchronized requires an Objective-C object type (%0 invalid)">; def error_rethrow_used_outside_catch : Error< "@throw (rethrow) used outside of a @catch block">; def err_attribute_multiple_objc_gc : Error< "multiple garbage collection attributes specified for type">; def err_catch_param_not_objc_type : Error< "@catch parameter is not a pointer to an interface type">; def err_illegal_qualifiers_on_catch_parm : Error< "illegal qualifiers on @catch parameter">; def err_storage_spec_on_catch_parm : Error< "@catch parameter cannot have storage specifier '%0'">; def warn_register_objc_catch_parm : Warning< "'register' storage specifier on @catch parameter will be ignored">; def err_qualified_objc_catch_parm : Error< "@catch parameter declarator cannot be qualified">; def warn_objc_pointer_cxx_catch_fragile : Warning< "cannot catch an exception thrown with @throw in C++ in the non-unified " "exception model">, InGroup; def err_objc_object_catch : Error< "can't catch an Objective-C object by value">; def err_incomplete_type_objc_at_encode : Error< "'@encode' of incomplete type %0">; def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " "use @synthesize, @dynamic or provide a method implementation " "in this class implementation">, InGroup; def warn_setter_getter_impl_required_in_category : Warning< "property %0 requires method %1 to be defined - " "use @dynamic or provide a method implementation in this category">, InGroup; def note_parameter_named_here : Note< "passing argument to parameter %0 here">; def note_parameter_here : Note< "passing argument to parameter here">; def note_method_return_type_change : Note< "compiler has implicitly changed method %0 return type">; // C++ casts // These messages adhere to the TryCast pattern: %0 is an int specifying the // cast type, %1 is the source type, %2 is the destination type. def err_bad_reinterpret_cast_overload : Error< "reinterpret_cast cannot resolve overloaded function %0 to type %1">; def warn_reinterpret_different_from_static : Warning< "'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its " "%select{virtual base|base at non-zero offset}2 %1 behaves differently from " "'static_cast'">, InGroup; def note_reinterpret_updowncast_use_static: Note< "use 'static_cast' to adjust the pointer correctly while " "%select{upcasting|downcasting}0">; def err_bad_static_cast_overload : Error< "address of overloaded function %0 cannot be static_cast to type %1">; def err_bad_cstyle_cast_overload : Error< "address of overloaded function %0 cannot be cast to type %1">; def err_bad_cxx_cast_generic : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 is not allowed">; def err_bad_cxx_cast_rvalue : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from rvalue to reference type %2">; def err_bad_cxx_cast_bitfield : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from bit-field lvalue to reference type %2">; def err_bad_cxx_cast_qualifiers_away : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 casts away qualifiers">; def err_bad_const_cast_dest : Error< "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " "which is not a reference, pointer-to-object, or pointer-to-data-member">; def ext_cast_fn_obj : Extension< "cast between pointer-to-function and pointer-to-object is an extension">; def warn_cxx98_compat_cast_fn_obj : Warning< "cast between pointer-to-function and pointer-to-object is incompatible with C++98">, InGroup, DefaultIgnore; def err_bad_reinterpret_cast_small_int : Error< "cast from pointer to smaller type %2 loses information">; def err_bad_cxx_cast_vector_to_scalar_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to scalar %2 of different size">; def err_bad_cxx_cast_scalar_to_vector_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " "to vector %2 of different size">; def err_bad_cxx_cast_vector_to_vector_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to vector %2 of different size">; def err_bad_lvalue_to_rvalue_cast : Error< "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " "not compatible">; def err_bad_static_cast_pointer_nonpointer : Error< "cannot cast from type %1 to pointer type %2">; def err_bad_static_cast_member_pointer_nonmp : Error< "cannot cast from type %1 to member pointer type %2">; def err_bad_cxx_cast_member_pointer_size : Error< "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer " "type %1 to member pointer type %2 of different size">; def err_bad_reinterpret_cast_reference : Error< "reinterpret_cast of a %0 to %1 needs its address, which is not allowed">; def warn_undefined_reinterpret_cast : Warning< "reinterpret_cast from %0 to %1 has undefined behavior">, InGroup, DefaultIgnore; // These messages don't adhere to the pattern. // FIXME: Display the path somehow better. def err_ambiguous_base_to_derived_cast : Error< "ambiguous cast from base %0 to derived %1:%2">; def err_static_downcast_via_virtual : Error< "cannot cast %0 to %1 via virtual base %2">; def err_downcast_from_inaccessible_base : Error< "cannot cast %select{private|protected}2 base class %1 to %0">; def err_upcast_to_inaccessible_base : Error< "cannot cast %0 to its %select{private|protected}2 base class %1">; def err_bad_dynamic_cast_not_ref_or_ptr : Error< "%0 is not a reference or pointer">; def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; // Other C++ expressions def err_need_header_before_typeid : Error< "you need to include before using the 'typeid' operator">; def err_need_header_before_ms_uuidof : Error< "you need to include before using the '__uuidof' operator">; def err_ms___leave_not_in___try : Error< "'__leave' statement not in __try block">; def err_uuidof_without_guid : Error< "cannot call operator __uuidof on a type with no GUID">; def err_uuidof_with_multiple_guids : Error< "cannot call operator __uuidof on a type with multiple GUIDs">; def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0">; def err_static_illegal_in_new : Error< "the 'static' modifier for the array size is not legal in new expressions">; def err_array_new_needs_size : Error< "array size must be specified in new expressions">; def err_bad_new_type : Error< "cannot allocate %select{function|reference}1 type %0 with new">; def err_new_incomplete_type : Error< "allocation of incomplete type %0">; def err_new_array_nonconst : Error< "only the first dimension of an allocated array may have dynamic size">; def err_new_array_init_args : Error< "array 'new' cannot have initialization arguments">; def ext_new_paren_array_nonconst : ExtWarn< "when type is in parentheses, array cannot have dynamic size">; def err_placement_new_non_placement_delete : Error< "'new' expression with placement arguments refers to non-placement " "'operator delete'">; def err_array_size_not_integral : Error< "array size expression must have integral or %select{|unscoped }0" "enumeration type, not %1">; def err_array_size_incomplete_type : Error< "array size expression has incomplete class type %0">; def err_array_size_explicit_conversion : Error< "array size expression of type %0 requires explicit conversion to type %1">; def note_array_size_conversion : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_array_size_ambiguous_conversion : Error< "ambiguous conversion of array size expression of type %0 to an integral or " "enumeration type">; def ext_array_size_conversion : Extension< "implicit conversion from array size expression of type %0 to " "%select{integral|enumeration}1 type %2 is a C++11 extension">, InGroup; def warn_cxx98_compat_array_size_conversion : Warning< "implicit conversion from array size expression of type %0 to " "%select{integral|enumeration}1 type %2 is incompatible with C++98">, InGroup, DefaultIgnore; def err_address_space_qualified_new : Error< "'new' cannot allocate objects of type %0 in address space '%1'">; def err_address_space_qualified_delete : Error< "'delete' cannot delete objects of type %0 in address space '%1'">; def err_default_init_const : Error< "default initialization of an object of const type %0" "%select{| without a user-provided default constructor}1">; def note_add_initializer : Note< "add an explicit initializer to initialize %0">; def err_delete_operand : Error<"cannot delete expression of type %0">; def ext_delete_void_ptr_operand : ExtWarn< "cannot delete expression with pointer-to-'void' type %0">, InGroup; def err_ambiguous_delete_operand : Error< "ambiguous conversion of delete expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behavior">, InGroup; def err_delete_incomplete_class_type : Error< "deleting incomplete class type %0; no conversions to pointer type">; def err_delete_explicit_conversion : Error< "converting delete expression from type %0 to type %1 invokes an explicit " "conversion function">; def note_delete_conversion : Note<"conversion to pointer type %0">; def warn_delete_array_type : Warning< "'delete' applied to a pointer-to-array type %0 treated as delete[]">; def err_no_suitable_delete_member_function_found : Error< "no suitable member %0 in %1">; def err_ambiguous_suitable_delete_member_function_found : Error< "multiple suitable %0 functions in %1">; def note_member_declared_here : Note< "member %0 declared here">; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated">, InGroup; def err_increment_decrement_enum : Error< "cannot %select{decrement|increment}0 expression of enum type %1">; def err_catch_incomplete_ptr : Error< "cannot catch pointer to incomplete type %0">; def err_catch_incomplete_ref : Error< "cannot catch reference to incomplete type %0">; def err_catch_incomplete : Error<"cannot catch incomplete type %0">; def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; def err_qualified_catch_declarator : Error< "exception declarator cannot be qualified">; def err_early_catch_all : Error<"catch-all handler must come last">; def err_bad_memptr_rhs : Error< "right hand operand to %0 has non-pointer-to-member type %1">; def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; def warn_exception_caught_by_earlier_handler : Warning< "exception of type %0 will be caught by earlier handler">; def note_previous_exception_handler : Note<"for type %0">; def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; def warn_non_virtual_dtor : Warning< "%0 has virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; def warn_delete_non_virtual_dtor : Warning< "delete called on %0 that has virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; def warn_delete_abstract_non_virtual_dtor : Warning< "delete called on %0 that is abstract but has non-virtual destructor">, InGroup; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup, DefaultIgnore; def note_hidden_overloaded_virtual_declared_here : Note< "hidden overloaded virtual function %q0 declared here" "%select{|: different classes%diff{ ($ vs $)|}2,3" "|: different number of parameters (%2 vs %3)" "|: type mismatch at %ordinal2 parameter%diff{ ($ vs $)|}3,4" "|: different return type%diff{ ($ vs $)|}2,3" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}2 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3)}1">; def warn_using_directive_in_header : Warning< "using namespace directive in global context in header">, InGroup, DefaultIgnore; def warn_overaligned_type : Warning< "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup, DefaultIgnore; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " "is of type %0">; def err_conditional_ambiguous : Error< "conditional expression is ambiguous; " "%diff{$ can be converted to $ and vice versa|" "types can be convert to each other}0,1">; def err_conditional_ambiguous_ovl : Error< "conditional expression is ambiguous; %diff{$ and $|types}0,1 " "can be converted to several common types">; def err_throw_incomplete : Error< "cannot throw object of incomplete type %0">; def err_throw_incomplete_ptr : Error< "cannot throw pointer to object of incomplete type %0">; def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; let CategoryName = "Lambda Issue" in { def err_capture_more_than_once : Error< "%0 can appear only once in a capture list">; def err_reference_capture_with_reference_default : Error< "'&' cannot precede a capture when the capture default is '&'">; def err_this_capture_with_copy_default : Error< "'this' cannot be explicitly captured when the capture default is '='">; def err_copy_capture_with_copy_default : Error< "'&' must precede a capture when the capture default is '='">; def err_capture_does_not_name_variable : Error< "%0 in capture list does not name a variable">; def err_capture_non_automatic_variable : Error< "%0 cannot be captured because it does not have automatic storage " "duration">; def err_this_capture : Error< "'this' cannot be %select{implicitly |}0captured in this context">; def err_lambda_capture_anonymous_var : Error< "unnamed variable cannot be implicitly captured in a lambda expression">; def err_lambda_capture_flexarray_type : Error< "variable %0 with flexible array member cannot be captured in " "a lambda expression">; def err_lambda_impcap : Error< "variable %0 cannot be implicitly captured in a lambda with no " "capture-default specified">; def note_lambda_decl : Note<"lambda expression begins here">; def err_lambda_unevaluated_operand : Error< "lambda expression in an unevaluated operand">; def err_lambda_in_constant_expression : Error< "a lambda expression may not appear inside of a constant expression">; def err_lambda_return_init_list : Error< "cannot deduce lambda return type from initializer list">; def err_lambda_capture_default_arg : Error< "lambda expression in default argument cannot capture any entity">; def err_lambda_incomplete_result : Error< "incomplete result type %0 in lambda expression">; def err_noreturn_lambda_has_return_expr : Error< "lambda declared 'noreturn' should not return">; def warn_maybe_falloff_nonvoid_lambda : Warning< "control may reach end of non-void lambda">, InGroup; def warn_falloff_nonvoid_lambda : Warning< "control reaches end of non-void lambda">, InGroup; def err_access_lambda_capture : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "capture of variable '%0' as type %1 calls %select{private|protected}3 " "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, AccessControl; def note_lambda_to_block_conv : Note< "implicit capture of lambda object due to conversion to block pointer " "here">; // C++14 lambda init-captures. def warn_cxx11_compat_init_capture : Warning< "initialized lambda captures are incompatible with C++ standards " "before C++14">, InGroup, DefaultIgnore; def ext_init_capture : ExtWarn< "initialized lambda captures are a C++14 extension">, InGroup; def err_init_capture_no_expression : Error< "initializer missing for lambda capture %0">; def err_init_capture_multiple_expressions : Error< "initializer for lambda capture %0 contains multiple expressions">; def err_init_capture_paren_braces : Error< "cannot deduce type for lambda capture %0 from " "parenthesized initializer list">; def err_init_capture_deduction_failure : Error< "cannot deduce type for lambda capture %0 from initializer of type %2">; def err_init_capture_deduction_failure_from_init_list : Error< "cannot deduce type for lambda capture %0 from initializer list">; } def err_return_in_captured_stmt : Error< "cannot return from %0">; def err_capture_block_variable : Error< "__block variable %0 cannot be captured in a " "%select{lambda expression|captured statement}1">; def err_operator_arrow_circular : Error< "circular pointer delegation detected">; def err_operator_arrow_depth_exceeded : Error< "use of 'operator->' on type %0 would invoke a sequence of more than %1 " "'operator->' calls">; def note_operator_arrow_here : Note< "'operator->' declared here produces an object of type %0">; def note_operator_arrows_suppressed : Note< "(skipping %0 'operator->'%s0 in backtrace)">; def note_operator_arrow_depth : Note< "use -foperator-arrow-depth=N to increase 'operator->' limit">; def err_pseudo_dtor_base_not_scalar : Error< "object expression of non-scalar type %0 cannot be used in a " "pseudo-destructor expression">; def ext_pseudo_dtor_on_void : ExtWarn< "pseudo-destructors on type void are a Microsoft extension">, InGroup; def err_pseudo_dtor_type_mismatch : Error< "the type of object expression " "%diff{($) does not match the type being destroyed ($)|" "does not match the type being destroyed}0,1 " "in pseudo-destructor expression">; def err_pseudo_dtor_call_with_args : Error< "call to pseudo-destructor cannot have any arguments">; def err_dtor_expr_without_call : Error< "%select{destructor reference|pseudo-destructor expression}0 must be " "called immediately with '()'">; def err_pseudo_dtor_destructor_non_type : Error< "%0 does not refer to a type name in pseudo-destructor expression; expected " "the name of type %1">; def err_invalid_use_of_function_type : Error< "a function type is not allowed here">; def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; def err_type_defined_in_condition : Error< "types may not be defined in conditions">; def err_typecheck_bool_condition : Error< "value of type %0 is not contextually convertible to 'bool'">; def err_typecheck_ambiguous_condition : Error< "conversion %diff{from $ to $|between types}0,1 is ambiguous">; def err_typecheck_nonviable_condition : Error< "no viable conversion%diff{ from $ to $|}0,1">; def err_typecheck_nonviable_condition_incomplete : Error< "no viable conversion%diff{ from $ to incomplete type $|}0,1">; def err_typecheck_deleted_function : Error< "conversion function %diff{from $ to $|between types}0,1 " "invokes a deleted function">; def err_expected_class_or_namespace : Error<"%0 is not a class" "%select{ or namespace|, namespace, or scoped enumeration}1">; def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " "because namespace %1 does not enclose namespace %2">; def err_invalid_declarator_global_scope : Error< "definition or redeclaration of %0 cannot name the global scope">; def err_invalid_declarator_in_function : Error< "definition or redeclaration of %0 not allowed inside a function">; def err_invalid_declarator_in_block : Error< "definition or redeclaration of %0 not allowed inside a block">; def err_not_tag_in_scope : Error< "no %select{struct|interface|union|class|enum}0 named %1 in %2">; def err_no_typeid_with_fno_rtti : Error< "cannot use typeid with -fno-rtti">; def err_no_dynamic_cast_with_fno_rtti : Error< "cannot use dynamic_cast with -fno-rtti">; def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; def err_incomplete_object_call : Error< "incomplete type in call to object of type %0">; def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup; // Completely identical except off by default. def warn_condition_is_idiomatic_assignment : Warning<"using the result " "of an assignment as a condition without parentheses">, InGroup>, DefaultIgnore; def note_condition_assign_to_comparison : Note< "use '==' to turn this assignment into an equality comparison">; def note_condition_or_assign_to_comparison : Note< "use '!=' to turn this compound assignment into an inequality comparison">; def note_condition_assign_silence : Note< "place parentheses around the assignment to silence this warning">; def warn_equality_with_extra_parens : Warning<"equality comparison with " "extraneous parentheses">, InGroup; def note_equality_comparison_to_assign : Note< "use '=' to turn this equality comparison into an assignment">; def note_equality_comparison_silence : Note< "remove extraneous parentheses around the comparison to silence this warning">; // assignment related diagnostics (also for argument passing, returning, etc). // In most of these diagnostics the %2 is a value from the // Sema::AssignmentAction enumeration def err_typecheck_convert_incompatible : Error< "%select{%diff{assigning to $ from incompatible type $|" "assigning to type from incompatible type}0,1" "|%diff{passing $ to parameter of incompatible type $|" "passing type to parameter of incompatible type}0,1" "|%diff{returning $ from a function with incompatible result type $|" "returning type from a function with incompatible result type}0,1" "|%diff{converting $ to incompatible type $|" "converting type to incompatible type}0,1" "|%diff{initializing $ with an expression of incompatible type $|" "initializing type with an expression of incompatible type}0,1" "|%diff{sending $ to parameter of incompatible type $|" "sending type to parameter of incompatible type}0,1" "|%diff{casting $ to incompatible type $|" "casting type to incompatible type}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3" "%select{|: different classes%diff{ ($ vs $)|}5,6" "|: different number of parameters (%5 vs %6)" "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" "|: different return type%diff{ ($ vs $)|}5,6" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}6)}4">; def err_typecheck_missing_return_type_incompatible : Error< "%diff{return type $ must match previous return type $|" "return type must match previous return type}0,1 when %select{block " "literal|lambda expression}2 has unspecified explicit return type">; def not_incomplete_class_and_qualified_id : Note< "conformance of forward class %0 to protocol %1 can not be confirmed">; def warn_incompatible_qualified_id : Warning< "%select{%diff{assigning to $ from incompatible type $|" "assigning to type from incompatible type}0,1" "|%diff{passing $ to parameter of incompatible type $|" "passing type to parameter of incompatible type}0,1" "|%diff{returning $ from a function with incompatible result type $|" "returning type from a function with incompatible result type}0,1" "|%diff{converting $ to incompatible type $|" "converting type to incompatible type}0,1" "|%diff{initializing $ with an expression of incompatible type $|" "initializing type with an expression of incompatible type}0,1" "|%diff{sending $ to parameter of incompatible type $|" "sending type to parameter of incompatible type}0,1" "|%diff{casting $ to incompatible type $|" "casting type to incompatible type}0,1}2">; def ext_typecheck_convert_pointer_int : ExtWarn< "incompatible pointer to integer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_int_pointer : ExtWarn< "incompatible integer to pointer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_pointer_void_func : Extension< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " converts between void pointer and function pointer">; def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " converts between pointers to integer types with different sign">, InGroup>; def ext_typecheck_convert_incompatible_pointer : ExtWarn< "incompatible pointer types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_discards_qualifiers : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " discards qualifiers">, InGroup; def ext_nested_pointer_qualifier_mismatch : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " discards qualifiers in nested pointer types">, InGroup; def warn_incompatible_vectors : Warning< "incompatible vector types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">, InGroup, DefaultIgnore; def err_int_to_block_pointer : Error< "invalid block pointer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">; def err_typecheck_convert_incompatible_block_pointer : Error< "incompatible block pointer types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">; def err_typecheck_incompatible_address_space : Error< "%select{%diff{assigning $ to $|assigning to different types}1,0" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes address space of pointer">; def err_typecheck_incompatible_ownership : Error< "%select{%diff{assigning $ to $|assigning to different types}1,0" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes retain/release properties of pointer">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; def err_typecheck_array_not_modifiable_lvalue : Error< "array type %0 is not assignable">; def err_typecheck_non_object_not_modifiable_lvalue : Error< "non-object type %0 is not assignable">; def err_typecheck_expression_not_modifiable_lvalue : Error< "expression is not assignable">; def err_typecheck_incomplete_type_not_modifiable_lvalue : Error< "incomplete type %0 is not assignable">; def err_typecheck_lvalue_casts_not_supported : Error< "assignment to cast is illegal, lvalue casts are not supported">; def err_typecheck_duplicate_vector_components_not_mlvalue : Error< "vector is not assignable (contains duplicate components)">; def err_block_decl_ref_not_modifiable_lvalue : Error< "variable is not assignable (missing __block type specifier)">; def err_lambda_decl_ref_not_modifiable_lvalue : Error< "cannot assign to a variable captured by copy in a non-mutable lambda">; def err_typecheck_call_not_function : Error< "called object type %0 is not a function or function pointer">; def err_call_incomplete_return : Error< "calling function with incomplete return type %0">; def err_call_function_incomplete_return : Error< "calling %0 with incomplete return type %1">; def err_call_incomplete_argument : Error< "argument type %0 is incomplete">; def err_typecheck_call_too_few_args : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2">; def err_typecheck_call_too_few_args_one : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "single argument %1 was not specified">; def err_typecheck_call_too_few_args_at_least : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at least %1, have %2">; def err_typecheck_call_too_few_args_at_least_one : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "at least argument %1 must be specified">; def err_typecheck_call_too_few_args_suggest : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2; did you mean %3?">; def err_typecheck_call_too_few_args_at_least_suggest : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at least %1, have %2; did you mean %3?">; def err_typecheck_call_too_many_args : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2">; def err_typecheck_call_too_many_args_one : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected single argument %1, have %2 arguments">; def err_typecheck_call_too_many_args_at_most : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2">; def err_typecheck_call_too_many_args_at_most_one : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most single argument %1, have %2 arguments">; def err_typecheck_call_too_many_args_suggest : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2; did you mean %3?">; def err_typecheck_call_too_many_args_at_most_suggest : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2; did you mean %3?">; def err_arc_typecheck_convert_incompatible_pointer : Error< "incompatible pointer types passing retainable parameter of type %0" "to a CF function expecting %1 type">; def err_builtin_fn_use : Error<"builtin functions must be directly called">; def warn_call_wrong_number_of_arguments : Warning< "too %select{few|many}0 arguments in call to %1">; def err_atomic_builtin_must_be_pointer : Error< "address argument to atomic builtin must be a pointer (%0 invalid)">; def err_atomic_builtin_must_be_pointer_intptr : Error< "address argument to atomic builtin must be a pointer to integer or pointer" " (%0 invalid)">; def err_atomic_builtin_must_be_pointer_intfltptr : Error< "address argument to atomic builtin must be a pointer to integer," " floating-point or pointer (%0 invalid)">; def err_atomic_builtin_pointer_size : Error< "address argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte " "type (%0 invalid)">; def err_atomic_exclusive_builtin_pointer_size : Error< "address argument to load or store exclusive builtin must be a pointer to" " 1,2,4 or 8 byte type (%0 invalid)">; def err_atomic_op_needs_atomic : Error< "address argument to atomic operation must be a pointer to _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_non_const_atomic : Error< "address argument to atomic operation must be a pointer to non-const _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; def err_atomic_op_needs_atomic_int_or_ptr : Error< "address argument to atomic operation must be a pointer to %select{|atomic }0" "integer or pointer (%1 invalid)">; def err_atomic_op_bitwise_needs_atomic_int : Error< "address argument to bitwise atomic operation must be a pointer to " "%select{|atomic }0integer (%1 invalid)">; def warn_atomic_op_has_invalid_memory_order : Warning< "memory order argument to atomic operation is invalid">, InGroup>; def err_atomic_load_store_uses_lib : Error< "atomic %select{load|store}0 requires runtime support that is not " "available for this target">; def err_deleted_function_use : Error<"attempt to use a deleted function">; def err_kern_type_not_void_return : Error< "kernel function type %0 must have void return type">; def err_config_scalar_return : Error< "CUDA special function 'cudaConfigureCall' must have scalar return type">; def err_kern_call_not_global_function : Error< "kernel call to non-global function %0">; def err_global_call_not_config : Error< "call to global function %0 not configured">; def err_ref_bad_target : Error< "reference to %select{__device__|__global__|__host__|__host__ __device__}0 " "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; def warn_non_pod_vararg_with_format_string : Warning< "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">, InGroup, DefaultError; // The arguments to this diagnostic should match the warning above. def err_cannot_pass_objc_interface_to_vararg_format : Error< "cannot pass object with interface type %1 by value to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">; def err_cannot_pass_objc_interface_to_vararg : Error< "cannot pass object with interface type %0 by value through variadic " "%select{function|block|method|constructor}1">; def warn_cannot_pass_non_pod_arg_to_vararg : Warning< "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic" " %select{function|block|method|constructor}2; call will abort at runtime">, InGroup, DefaultError; def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning< "passing object of trivial but non-POD type %0 through variadic" " %select{function|block|method|constructor}1 is incompatible with C++98">, InGroup, DefaultIgnore; def warn_pass_class_arg_to_vararg : Warning< "passing object of class type %0 through variadic " "%select{function|block|method|constructor}1" "%select{|; did you mean to call '%3'?}2">, InGroup, DefaultIgnore; def err_cannot_pass_to_vararg : Error< "cannot pass %select{expression of type %1|initializer list}0 to variadic " "%select{function|block|method|constructor}2">; def err_cannot_pass_to_vararg_format : Error< "cannot pass %select{expression of type %1|initializer list}0 to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">; def err_typecheck_call_invalid_ordered_compare : Error< "ordered compare requires two args of floating point type" "%diff{ ($ and $)|}0,1">; def err_typecheck_call_invalid_unary_fp : Error< "floating point classification requires argument of floating point type " "(passed in %0)">; def err_typecheck_cond_expect_scalar : Error< "used type %0 where arithmetic or pointer type is required">; def ext_typecheck_cond_one_void : Extension< "C99 forbids conditional expressions with only one void side">; def err_typecheck_cond_expect_scalar_or_vector : Error< "used type %0 where arithmetic, pointer, or vector type is required">; def err_typecheck_cast_to_incomplete : Error< "cast to incomplete type %0">; def ext_typecheck_cast_nonscalar : Extension< "C99 forbids casting nonscalar type %0 to the same type">; def ext_typecheck_cast_to_union : Extension< "cast to union type is a GNU extension">, InGroup; def err_typecheck_cast_to_union_no_type : Error< "cast to union type from type %0 not present in union">; def err_cast_pointer_from_non_pointer_int : Error< "operand of type %0 cannot be cast to a pointer type">; def warn_cast_pointer_from_sel : Warning< "cast of type %0 to %1 is deprecated; use sel_getName instead">, InGroup; def warn_function_def_in_objc_container : Warning< "function definition inside an Objective-C container is deprecated">, InGroup; def warn_bad_function_cast : Warning< "cast from function call of type %0 to non-matching type %1">, InGroup, DefaultIgnore; def err_cast_pointer_to_non_pointer_int : Error< "pointer cannot be cast to type %0">; def err_typecheck_expect_scalar_operand : Error< "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types%diff{ ($ and $)|}0,1">; def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn< "incompatible operand types%diff{ ($ and $)|}0,1 use non-standard composite " "pointer type %2">; def err_cast_selector_expr : Error< "cannot type cast @selector expression">; def ext_typecheck_cond_incompatible_pointers : ExtWarn< "pointer type mismatch%diff{ ($ and $)|}0,1">, InGroup>; def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< "pointer/integer type mismatch in conditional expression" "%diff{ ($ and $)|}0,1">, InGroup>; def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, InGroup; def warn_unused_voidptr : Warning< "expression result unused; should this cast be to 'void'?">, InGroup; def warn_unused_property_expr : Warning< "property access result unused - getters should not be used for side effects">, InGroup; def warn_unused_container_subscript_expr : Warning< "container access result unused - container access should not be used for side effects">, InGroup; def warn_unused_call : Warning< "ignoring return value of function declared with %0 attribute">, InGroup; def warn_side_effects_unevaluated_context : Warning< "expression with side effects has no effect in an unevaluated context">, InGroup; def warn_side_effects_typeid : Warning< "expression with side effects will be evaluated despite being used as an " "operand to 'typeid'">, InGroup; def warn_unused_result : Warning< "ignoring return value of function declared with warn_unused_result " "attribute">, InGroup>; def warn_unused_volatile : Warning< "expression result unused; assign into a variable to force a volatile load">, InGroup>; def warn_unused_comparison : Warning< "%select{%select{|in}1equality|relational}0 comparison result unused">, InGroup; def note_inequality_comparison_to_or_assign : Note< "use '|=' to turn this inequality comparison into an or-assignment">; def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; def err_dimension_expr_not_constant_integer : Error< "dimension expression does not evaluate to a constant unsigned int">; def err_typecheck_cond_incompatible_operands_null : Error< "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; def ext_empty_struct_union : Extension< "empty %select{struct|union}0 is a GNU extension">, InGroup; def ext_no_named_members_in_struct_union : Extension< "%select{struct|union}0 without named members is a GNU extension">, InGroup; def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0" "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, InGroup, DefaultIgnore; def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0" "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, InGroup; def warn_cast_qual : Warning<"cast from %0 to %1 drops %select{const and " "volatile qualifiers|const qualifier|volatile qualifier}2">, InGroup, DefaultIgnore; def warn_cast_qual2 : Warning<"cast from %0 to %1 must have all intermediate " "pointers const qualified to be safe">, InGroup, DefaultIgnore; } // End of general sema category. // inline asm. let CategoryName = "Inline Assembly Issue" in { def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; def err_asm_invalid_output_constraint : Error< "invalid output constraint '%0' in asm">; def err_asm_invalid_lvalue_in_input : Error< "invalid lvalue in asm input for constraint '%0'">; def err_asm_invalid_input_constraint : Error< "invalid input constraint '%0' in asm">; def err_asm_immediate_expected : Error<"constraint '%0' expects " "an integer constant expression">; def err_asm_invalid_type_in_input : Error< "invalid type %0 in asm input for constraint '%1'">; def err_asm_tying_incompatible_types : Error< "unsupported inline asm: input with type " "%diff{$ matching output with type $|}0,1">; def err_asm_unexpected_constraint_alternatives : Error< "asm constraint has an unexpected number of alternatives: %0 vs %1">; def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">; def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; def err_asm_bad_register_type : Error<"bad type for named register variable">; def err_asm_invalid_input_size : Error< "invalid input size for constraint '%0'">; def err_asm_invalid_output_size : Error< "invalid output size for constraint '%0'">; def err_invalid_asm_cast_lvalue : Error< "invalid use of a cast in a inline asm context requiring an l-value: " "remove the cast or build with -fheinous-gnu-extensions">; def err_invalid_asm_value_for_constraint : Error <"value '%0' out of range for constraint '%1'">; def warn_asm_label_on_auto_decl : Warning< "ignored asm label '%0' on automatic variable">; def warn_invalid_asm_cast_lvalue : Warning< "invalid use of a cast in an inline asm context requiring an l-value: " "accepted due to -fheinous-gnu-extensions, but clang may remove support " "for this in the future">; def warn_asm_mismatched_size_modifier : Warning< "value size does not match register size specified by the constraint " "and modifier">, InGroup; def note_asm_missing_constraint_modifier : Note< "use constraint modifier \"%0\"">; } let CategoryName = "Semantic Issue" in { def err_invalid_conversion_between_vectors : Error< "invalid conversion between vector type%diff{ $ and $|}0,1 of different " "size">; def err_invalid_conversion_between_vector_and_integer : Error< "invalid conversion between vector type %0 and integer type %1 " "of different size">; def err_opencl_function_pointer_variable : Error< "pointers to functions are not allowed">; def err_opencl_taking_function_address : Error< "taking address of function is not allowed">; def err_invalid_conversion_between_vector_and_scalar : Error< "invalid conversion between vector type %0 and scalar type %1">; // C++ member initializers. def err_only_constructors_take_base_inits : Error< "only constructors take base initializers">; def err_multiple_mem_initialization : Error < "multiple initializations given for non-static member %0">; def err_multiple_mem_union_initialization : Error < "initializing multiple members of union">; def err_multiple_base_initialization : Error < "multiple initializations given for base %0">; def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; def warn_initializer_out_of_order : Warning< "%select{field|base class}0 %1 will be initialized after " "%select{field|base}2 %3">, InGroup, DefaultIgnore; def warn_abstract_vbase_init_ignored : Warning< "initializer for virtual base class %0 of abstract class %1 " "will never be used">, InGroup>, DefaultIgnore; def err_base_init_does_not_name_class : Error< "constructor initializer %0 does not name a class">; def err_base_init_direct_and_virtual : Error< "base class initializer %0 names both a direct base class and an " "inherited virtual base class">; def err_not_direct_base_or_virtual : Error< "type %0 is not a direct or virtual base of %1">; def err_in_class_initializer_non_const : Error< "non-const static data member must be initialized out of line">; def err_in_class_initializer_volatile : Error< "static const volatile data member must be initialized out of line">; def err_in_class_initializer_bad_type : Error< "static data member of type %0 must be initialized out of line">; def ext_in_class_initializer_float_type : ExtWarn< "in-class initializer for static data member of type %0 is a GNU extension">, InGroup; def ext_in_class_initializer_float_type_cxx11 : ExtWarn< "in-class initializer for static data member of type %0 requires " "'constexpr' specifier">, InGroup, DefaultError; def note_in_class_initializer_float_type_cxx11 : Note<"add 'constexpr'">; def err_in_class_initializer_literal_type : Error< "in-class initializer for static data member of type %0 requires " "'constexpr' specifier">; def err_in_class_initializer_non_constant : Error< "in-class initializer for static data member is not a constant expression">; def err_in_class_initializer_not_yet_parsed : Error<"cannot use defaulted default constructor of %0 within the class " "outside of member functions because %1 has an initializer">; def err_in_class_initializer_not_yet_parsed_outer_class : Error<"cannot use defaulted default constructor of %0 within " "%1 outside of member functions because %2 has an initializer">; def ext_in_class_initializer_non_constant : Extension< "in-class initializer for static data member is not a constant expression; " "folding it to a constant is a GNU extension">, InGroup; def err_thread_dynamic_init : Error< "initializer for thread-local variable must be a constant expression">; def err_thread_nontrivial_dtor : Error< "type of thread-local variable has non-trivial destruction">; def note_use_thread_local : Note< "use 'thread_local' to allow this">; // C++ anonymous unions and GNU anonymous structs/unions def ext_anonymous_union : Extension< "anonymous unions are a C11 extension">, InGroup; def ext_gnu_anonymous_struct : Extension< "anonymous structs are a GNU extension">, InGroup; def ext_c11_anonymous_struct : Extension< "anonymous structs are a C11 extension">, InGroup; def err_anonymous_union_not_static : Error< "anonymous unions at namespace or global scope must be declared 'static'">; def err_anonymous_union_with_storage_spec : Error< "anonymous union at class scope must not have a storage specifier">; def err_anonymous_struct_not_member : Error< "anonymous %select{structs|structs and classes}0 must be " "%select{struct or union|class}0 members">; def err_anonymous_union_member_redecl : Error< "member of anonymous union redeclares %0">; def err_anonymous_struct_member_redecl : Error< "member of anonymous struct redeclares %0">; def err_anonymous_record_with_type : Error< "types cannot be declared in an anonymous %select{struct|union}0">; def ext_anonymous_record_with_type : Extension< "types declared in an anonymous %select{struct|union}0 are a Microsoft " "extension">, InGroup; def ext_anonymous_record_with_anonymous_type : Extension< "anonymous types declared in an anonymous %select{struct|union}0 " "are an extension">, InGroup>; def err_anonymous_record_with_function : Error< "functions cannot be declared in an anonymous %select{struct|union}0">; def err_anonymous_record_with_static : Error< "static members cannot be declared in an anonymous %select{struct|union}0">; def err_anonymous_record_bad_member : Error< "anonymous %select{struct|union}0 can only contain non-static data members">; def err_anonymous_record_nonpublic_member : Error< "anonymous %select{struct|union}0 cannot contain a " "%select{private|protected}1 data member">; def ext_ms_anonymous_record : ExtWarn< "anonymous %select{structs|unions}0 are a Microsoft extension">, InGroup; // C++ local classes def err_reference_to_local_var_in_enclosing_function : Error< "reference to local variable %0 declared in enclosing function %1">; def err_reference_to_local_var_in_enclosing_block : Error< "reference to local variable %0 declared in enclosing block literal">; def err_reference_to_local_var_in_enclosing_lambda : Error< "reference to local variable %0 declared in enclosing lambda expression">; def err_reference_to_local_var_in_enclosing_context : Error< "reference to local variable %0 declared in enclosing context">; def err_static_data_member_not_allowed_in_local_class : Error< "static data member %0 not allowed in local class %1">; // C++ derived classes def err_base_clause_on_union : Error<"unions cannot have base classes">; def err_base_must_be_class : Error<"base specifier must name a class">; def err_union_as_base_class : Error<"unions cannot be base classes">; def err_circular_inheritance : Error< "circular inheritance between %0 and %1">; def err_base_class_has_flexible_array_member : Error< "base class %0 has a flexible array member">; def err_incomplete_base_class : Error<"base class has incomplete type">; def err_duplicate_base_class : Error< "base class %0 specified more than once as a direct base class">; // FIXME: better way to display derivation? Pass entire thing into diagclient? def err_ambiguous_derived_to_base_conv : Error< "ambiguous conversion from derived class %0 to base class %1:%2">; def err_ambiguous_memptr_conv : Error< "ambiguous conversion from pointer to member of %select{base|derived}0 " "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; def err_memptr_conv_via_virtual : Error< "conversion from pointer to member of class %0 to pointer to member " "of class %1 via virtual base %2 is not allowed">; // C++ member name lookup def err_ambiguous_member_multiple_subobjects : Error< "non-static member %0 found in multiple base-class subobjects of type %1:%2">; def err_ambiguous_member_multiple_subobject_types : Error< "member %0 found in multiple base classes of different types">; def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a " "declaration in a different namespace">; def note_hidden_tag : Note<"type declaration hidden">; def note_hiding_object : Note<"declaration hides type">; // C++ operator overloading def err_operator_overload_needs_class_or_enum : Error< "overloaded %0 must have at least one parameter of class " "or enumeration type">; def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; def err_operator_overload_static : Error< "overloaded %0 cannot be a static member function">; def err_operator_overload_default_arg : Error< "parameter of overloaded %0 cannot have a default argument">; def err_operator_overload_must_be : Error< "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator " "(has %1 parameter%s1)">; def err_operator_overload_must_be_member : Error< "overloaded %0 must be a non-static member function">; def err_operator_overload_post_incdec_must_be_int : Error< "parameter of overloaded post-%select{increment|decrement}1 operator must " "have type 'int' (not %0)">; // C++ allocation and deallocation functions. def err_operator_new_delete_declared_in_namespace : Error< "%0 cannot be declared inside a namespace">; def err_operator_new_delete_declared_static : Error< "%0 cannot be declared static in global scope">; def ext_operator_new_delete_declared_inline : ExtWarn< "replacement function %0 cannot be declared 'inline'">, InGroup>; def err_operator_new_delete_invalid_result_type : Error< "%0 must return type %1">; def err_operator_new_delete_dependent_result_type : Error< "%0 cannot have a dependent return type; use %1 instead">; def err_operator_new_delete_too_few_parameters : Error< "%0 must have at least one parameter">; def err_operator_new_delete_template_too_few_parameters : Error< "%0 template must have at least two parameters">; def warn_operator_new_returns_null : Warning< "%0 should not return a null pointer unless it is declared 'throw()'" "%select{| or 'noexcept'}1">, InGroup; def err_operator_new_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; " "use size_t (%1) instead">; def err_operator_new_param_type : Error< "%0 takes type size_t (%1) as first parameter">; def err_operator_new_default_arg: Error< "parameter of %0 cannot have a default argument">; def err_operator_delete_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; use %1 instead">; def err_operator_delete_param_type : Error< "first parameter of %0 must have type %1">; // C++ literal operators def err_literal_operator_outside_namespace : Error< "literal operator %0 must be in a namespace or global scope">; def err_literal_operator_id_outside_namespace : Error< "non-namespace scope '%0' cannot have a literal operator member">; def err_literal_operator_default_argument : Error< "literal operator cannot have a default argument">; // FIXME: This diagnostic sucks def err_literal_operator_params : Error< "parameter declaration for literal operator %0 is not valid">; def err_literal_operator_extern_c : Error< "literal operator must have C++ linkage">; def ext_string_literal_operator_template : ExtWarn< "string literal operator templates are a GNU extension">, InGroup; def warn_user_literal_reserved : Warning< "user-defined literal suffixes not starting with '_' are reserved" "%select{; no literal will invoke this operator|}0">, InGroup; // C++ conversion functions def err_conv_function_not_member : Error< "conversion function must be a non-static member function">; def err_conv_function_return_type : Error< "conversion function cannot have a return type">; def err_conv_function_with_params : Error< "conversion function cannot have any parameters">; def err_conv_function_variadic : Error< "conversion function cannot be variadic">; def err_conv_function_to_array : Error< "conversion function cannot convert to an array type">; def err_conv_function_to_function : Error< "conversion function cannot convert to a function type">; def err_conv_function_with_complex_decl : Error< "cannot specify any part of a return type in the " "declaration of a conversion function" "%select{" "; put the complete type after 'operator'|" "; use a typedef to declare a conversion to %1|" "; use an alias template to declare a conversion to %1|" "}0">; def err_conv_function_redeclared : Error< "conversion function cannot be redeclared">; def warn_conv_to_self_not_used : Warning< "conversion function converting %0 to itself will never be used">; def warn_conv_to_base_not_used : Warning< "conversion function converting %0 to its base class %1 will never be used">; def warn_conv_to_void_not_used : Warning< "conversion function converting %0 to %1 will never be used">; def warn_not_compound_assign : Warning< "use of unary operator that may be intended as compound assignment (%0=)">; // C++11 explicit conversion operators def ext_explicit_conversion_functions : ExtWarn< "explicit conversion functions are a C++11 extension">, InGroup; def warn_cxx98_compat_explicit_conversion_functions : Warning< "explicit conversion functions are incompatible with C++98">, InGroup, DefaultIgnore; // C++11 defaulted functions def err_defaulted_special_member_params : Error< "an explicitly-defaulted %select{|copy |move }0constructor cannot " "have default arguments">; def err_defaulted_special_member_variadic : Error< "an explicitly-defaulted %select{|copy |move }0constructor cannot " "be variadic">; def err_defaulted_special_member_return_type : Error< "explicitly-defaulted %select{copy|move}0 assignment operator must " "return %1">; def err_defaulted_special_member_quals : Error< "an explicitly-defaulted %select{copy|move}0 assignment operator may not " "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; def err_defaulted_special_member_volatile_param : Error< "the parameter for an explicitly-defaulted %select{<>|" "copy constructor|move constructor|copy assignment operator|" "move assignment operator|<>}0 may not be volatile">; def err_defaulted_special_member_move_const_param : Error< "the parameter for an explicitly-defaulted move " "%select{constructor|assignment operator}0 may not be const">; def err_defaulted_special_member_copy_const_param : Error< "the parameter for this explicitly-defaulted copy " "%select{constructor|assignment operator}0 is const, but a member or base " "requires it to be non-const">; def err_defaulted_copy_assign_not_ref : Error< "the parameter for an explicitly-defaulted copy assignment operator must be an " "lvalue reference type">; def err_incorrect_defaulted_exception_spec : Error< "exception specification of explicitly defaulted %select{default constructor|" "copy constructor|move constructor|copy assignment operator|move assignment " "operator|destructor}0 does not match the " "calculated one">; def err_incorrect_defaulted_constexpr : Error< "defaulted definition of %select{default constructor|copy constructor|" "move constructor|copy assignment operator|move assignment operator}0 " "is not constexpr">; def err_out_of_line_default_deletes : Error< "defaulting this %select{default constructor|copy constructor|move " "constructor|copy assignment operator|move assignment operator|destructor}0 " "would delete it after its first declaration">; def warn_vbase_moved_multiple_times : Warning< "defaulted move assignment operator of %0 will move assign virtual base " "class %1 multiple times">, InGroup>; def note_vbase_moved_here : Note< "%select{%1 is a virtual base class of base class %2 declared here|" "virtual base class %1 declared here}0">; def ext_implicit_exception_spec_mismatch : ExtWarn< "function previously declared with an %select{explicit|implicit}0 exception " "specification redeclared with an %select{implicit|explicit}0 exception " "specification">, InGroup>; def warn_ptr_arith_precedes_bounds : Warning< "the pointer decremented by %0 refers before the beginning of the array">, InGroup, DefaultIgnore; def warn_ptr_arith_exceeds_bounds : Warning< "the pointer incremented by %0 refers past the end of the array (that " "contains %1 element%s2)">, InGroup, DefaultIgnore; def warn_array_index_precedes_bounds : Warning< "array index %0 is before the beginning of the array">, InGroup; def warn_array_index_exceeds_bounds : Warning< "array index %0 is past the end of the array (which contains %1 " "element%s2)">, InGroup; def note_array_index_out_of_bounds : Note< "array %0 declared here">; def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; def warn_printf_data_arg_not_used : Warning< "data argument not used by format string">, InGroup; def warn_format_invalid_conversion : Warning< "invalid conversion specifier '%0'">, InGroup; def warn_printf_incomplete_specifier : Warning< "incomplete format specifier">, InGroup; def warn_missing_format_string : Warning< "format string missing">, InGroup; def warn_scanf_nonzero_width : Warning< "zero field width in scanf format string is unused">, InGroup; def warn_format_conversion_argument_type_mismatch : Warning< "format specifies type %0 but the argument has " "%select{type|underlying type}2 %1">, InGroup; def warn_format_argument_needs_cast : Warning< "%select{values of type|enum values with underlying type}2 '%0' should not " "be used as format arguments; add an explicit cast to %1 instead">, InGroup; def warn_printf_positional_arg_exceeds_data_args : Warning < "data argument position '%0' exceeds the number of data arguments (%1)">, InGroup; def warn_format_zero_positional_specifier : Warning< "position arguments in format strings start counting at 1 (not 0)">, InGroup; def warn_format_invalid_positional_specifier : Warning< "invalid position specified for %select{field width|field precision}0">, InGroup; def warn_format_mix_positional_nonpositional_args : Warning< "cannot mix positional and non-positional arguments in format string">, InGroup; def warn_static_array_too_small : Warning< "array argument is too small; contains %0 elements, callee requires at least %1">, InGroup; def note_callee_static_array : Note< "callee declares array parameter as static here">; def warn_empty_format_string : Warning< "format string is empty">, InGroup; def warn_format_string_is_wide_literal : Warning< "format string should not be a wide string">, InGroup; def warn_printf_format_string_contains_null_char : Warning< "format string contains '\\0' within the string body">, InGroup; def warn_printf_format_string_not_null_terminated : Warning< "format string is not null-terminated">, InGroup; def warn_printf_asterisk_missing_arg : Warning< "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">, InGroup; def warn_printf_asterisk_wrong_type : Warning< "field %select{width|precision}0 should have type %1, but argument has type %2">, InGroup; def warn_printf_nonsensical_optional_amount: Warning< "%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">, InGroup; def warn_printf_nonsensical_flag: Warning< "flag '%0' results in undefined behavior with '%1' conversion specifier">, InGroup; def warn_format_nonsensical_length: Warning< "length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">, InGroup; def warn_format_non_standard_positional_arg: Warning< "positional arguments are not supported by ISO C">, InGroup, DefaultIgnore; def warn_format_non_standard: Warning< "'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">, InGroup, DefaultIgnore; def warn_format_non_standard_conversion_spec: Warning< "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">, InGroup, DefaultIgnore; def warn_printf_ignored_flag: Warning< "flag '%0' is ignored when flag '%1' is present">, InGroup; def warn_scanf_scanlist_incomplete : Warning< "no closing ']' for '%%[' in scanf format string">, InGroup; def note_format_string_defined : Note<"format string is defined here">; def note_format_fix_specifier : Note<"did you mean to use '%0'?">; def note_printf_c_str: Note<"did you mean to call the %0 method?">; def warn_null_arg : Warning< "null passed to a callee that requires a non-null argument">, InGroup; def warn_null_ret : Warning< "null returned from %select{function|method}0 that requires a non-null return value">, InGroup; // CHECK: returning address/reference of stack memory def warn_ret_stack_addr : Warning< "address of stack memory associated with local variable %0 returned">, InGroup; def warn_ret_stack_ref : Warning< "reference to stack memory associated with local variable %0 returned">, InGroup; def warn_ret_local_temp_addr : Warning< "returning address of local temporary object">, InGroup; def warn_ret_local_temp_ref : Warning< "returning reference to local temporary object">, InGroup; def warn_ret_addr_label : Warning< "returning address of label, which is local">, InGroup; def err_ret_local_block : Error< "returning block that lives on the local stack">; def note_ref_var_local_bind : Note< "binding reference variable %0 here">; // Check for initializing a member variable with the address or a reference to // a constructor parameter. def warn_bind_ref_member_to_parameter : Warning< "binding reference member %0 to stack allocated parameter %1">, InGroup; def warn_init_ptr_member_to_parameter_addr : Warning< "initializing pointer member %0 with the stack address of parameter %1">, InGroup; def warn_bind_ref_member_to_temporary : Warning< "binding reference %select{|subobject of }1member %0 to a temporary value">, InGroup; def note_ref_or_ptr_member_declared_here : Note< "%select{reference|pointer}0 member declared here">; def note_ref_subobject_of_member_declared_here : Note< "member with reference subobject declared here">; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. // Array comparisons have similar warnings def warn_comparison_always : Warning< "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, InGroup; def warn_comparison_bitwise_always : Warning< "bitwise comparison always evaluates to %select{false|true}0">, InGroup; def warn_tautological_overlap_comparison : Warning< "overlapping comparisons always evaluate to %select{false|true}0">, InGroup, DefaultIgnore; def warn_stringcompare : Warning< "result of comparison against %select{a string literal|@encode}0 is " "unspecified (use strncmp instead)">, InGroup; def warn_identity_field_assign : Warning< "assigning %select{field|instance variable}0 to itself">, InGroup; // Type safety attributes def err_type_tag_for_datatype_not_ice : Error< "'type_tag_for_datatype' attribute requires the initializer to be " "an %select{integer|integral}0 constant expression">; def err_type_tag_for_datatype_too_large : Error< "'type_tag_for_datatype' attribute requires the initializer to be " "an %select{integer|integral}0 constant expression " "that can be represented by a 64 bit integer">; def warn_type_tag_for_datatype_wrong_kind : Warning< "this type tag was not designed to be used with this function">, InGroup; def warn_type_safety_type_mismatch : Warning< "argument type %0 doesn't match specified %1 type tag " "%select{that requires %3|}2">, InGroup; def warn_type_safety_null_pointer_required : Warning< "specified %0 type tag requires a null pointer">, InGroup; // Generic selections. def err_assoc_type_incomplete : Error< "type %0 in generic association incomplete">; def err_assoc_type_nonobject : Error< "type %0 in generic association not an object type">; def err_assoc_type_variably_modified : Error< "type %0 in generic association is a variably modified type">; def err_assoc_compatible_types : Error< "type %0 in generic association compatible with previously specified type %1">; def note_compat_assoc : Note< "compatible type %0 specified here">; def err_generic_sel_no_match : Error< "controlling expression type %0 not compatible with any generic association type">; def err_generic_sel_multi_match : Error< "controlling expression type %0 compatible with %1 generic association types">; // Blocks def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" " or pick a deployment target that supports them">; def err_block_returning_array_function : Error< "block cannot return %select{array|function}0 type %1">; // Builtin annotation def err_builtin_annotation_first_arg : Error< "first argument to __builtin_annotation must be an integer">; def err_builtin_annotation_second_arg : Error< "second argument to __builtin_annotation must be a non-wide string constant">; // CFString checking def err_cfstring_literal_not_string_constant : Error< "CFString literal is not a string constant">; def warn_cfstring_truncated : Warning< "input conversion stopped due to an input byte that does not " "belong to the input codeset UTF-8">, InGroup>; // Statements. def err_continue_not_in_loop : Error< "'continue' statement not in loop statement">; def err_break_not_in_loop_or_switch : Error< "'break' statement not in loop or switch statement">; def warn_loop_ctrl_binds_to_inner : Warning< "'%0' is bound to current loop, GCC binds it to the enclosing loop">, InGroup; def warn_break_binds_to_switch : Warning< "'break' is bound to loop, GCC binds it to switch">, InGroup; def err_default_not_in_switch : Error< "'default' statement not in switch statement">; def err_case_not_in_switch : Error<"'case' statement not in switch statement">; def warn_bool_switch_condition : Warning< "switch condition has boolean value">, InGroup; def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">, InGroup; def err_duplicate_case : Error<"duplicate case value '%0'">; def err_duplicate_case_differing_expr : Error< "duplicate case value: '%0' and '%1' both equal '%2'">; def warn_case_empty_range : Warning<"empty case range specified">; def warn_missing_case_for_condition : Warning<"no case matching constant switch condition '%0'">; def warn_def_missing_case1 : Warning< "enumeration value %0 not explicitly handled in switch">, InGroup, DefaultIgnore; def warn_def_missing_case2 : Warning< "enumeration values %0 and %1 not explicitly handled in switch">, InGroup, DefaultIgnore; def warn_def_missing_case3 : Warning< "enumeration values %0, %1, and %2 not explicitly handled in switch">, InGroup, DefaultIgnore; def warn_def_missing_cases : Warning< "%0 enumeration values not explicitly handled in switch: %1, %2, %3...">, InGroup, DefaultIgnore; def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">, InGroup; def warn_missing_case2 : Warning< "enumeration values %0 and %1 not handled in switch">, InGroup; def warn_missing_case3 : Warning< "enumeration values %0, %1, and %2 not handled in switch">, InGroup; def warn_missing_cases : Warning< "%0 enumeration values not handled in switch: %1, %2, %3...">, InGroup; def warn_unannotated_fallthrough : Warning< "unannotated fall-through between switch labels">, InGroup, DefaultIgnore; def warn_unannotated_fallthrough_per_function : Warning< "unannotated fall-through between switch labels in partly-annotated " "function">, InGroup, DefaultIgnore; def note_insert_fallthrough_fixit : Note< "insert '%0;' to silence this warning">; def note_insert_break_fixit : Note< "insert 'break;' to avoid fall-through">; def err_fallthrough_attr_wrong_target : Error< "clang::fallthrough attribute is only allowed on empty statements">; def note_fallthrough_insert_semi_fixit : Note<"did you forget ';'?">; def err_fallthrough_attr_outside_switch : Error< "fallthrough annotation is outside switch statement">; def warn_fallthrough_attr_invalid_placement : Warning< "fallthrough annotation does not directly precede switch label">, InGroup; def warn_fallthrough_attr_unreachable : Warning< "fallthrough annotation in unreachable code">, InGroup; def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, InGroup, DefaultIgnore; def warn_not_in_enum : Warning<"case value not in enumerated type %0">, InGroup; def warn_not_in_enum_assignment : Warning<"integer constant not in range " "of enumerated type %0">, InGroup>, DefaultIgnore; def err_typecheck_statement_requires_scalar : Error< "statement requires expression of scalar type (%0 invalid)">; def err_typecheck_statement_requires_integer : Error< "statement requires expression of integer type (%0 invalid)">; def err_multiple_default_labels_defined : Error< "multiple default labels in one switch">; def err_switch_multiple_conversions : Error< "multiple conversions from switch condition type %0 to an integral or " "enumeration type">; def note_switch_conversion : Note< "conversion to %select{integral|enumeration}0 type %1">; def err_switch_explicit_conversion : Error< "switch condition type %0 requires explicit conversion to %1">; def err_switch_incomplete_class_type : Error< "switch condition has incomplete class type %0">; def warn_empty_if_body : Warning< "if statement has empty body">, InGroup; def warn_empty_for_body : Warning< "for loop has empty body">, InGroup; def warn_empty_range_based_for_body : Warning< "range-based for loop has empty body">, InGroup; def warn_empty_while_body : Warning< "while loop has empty body">, InGroup; def warn_empty_switch_body : Warning< "switch statement has empty body">, InGroup; def note_empty_body_on_separate_line : Note< "put the semicolon on a separate line to silence this warning">; def err_va_start_used_in_non_variadic_function : Error< "'va_start' used in function with fixed args">; def warn_second_parameter_of_va_start_not_last_named_argument : Warning< "second parameter of 'va_start' not last named argument">, InGroup; def warn_va_start_of_reference_type_is_undefined : Warning< "'va_start' has undefined behavior with reference types">, InGroup; def err_first_argument_to_va_arg_not_of_type_va_list : Error< "first argument to 'va_arg' is of type %0 and not 'va_list'">; def err_second_parameter_to_va_arg_incomplete: Error< "second argument to 'va_arg' is of incomplete type %0">; def err_second_parameter_to_va_arg_abstract: Error< "second argument to 'va_arg' is of abstract type %0">; def warn_second_parameter_to_va_arg_not_pod : Warning< "second argument to 'va_arg' is of non-POD type %0">, InGroup, DefaultError; def warn_second_parameter_to_va_arg_ownership_qualified : Warning< "second argument to 'va_arg' is of ARC ownership-qualified type %0">, InGroup, DefaultError; def warn_second_parameter_to_va_arg_never_compatible : Warning< "second argument to 'va_arg' is of promotable type %0; this va_arg has " "undefined behavior because arguments will be promoted to %1">, InGroup; def warn_return_missing_expr : Warning< "non-void %select{function|method}1 %0 should return a value">, DefaultError, InGroup; def ext_return_missing_expr : ExtWarn< "non-void %select{function|method}1 %0 should return a value">, DefaultError, InGroup; def ext_return_has_expr : ExtWarn< "%select{void function|void method|constructor|destructor}1 %0 " "should not return a value">, DefaultError, InGroup; def ext_return_has_void_expr : Extension< "void %select{function|method|block}1 %0 should not return void expression">; def err_return_init_list : Error< "%select{void function|void method|constructor|destructor}1 %0 " "must not return a value">; def err_ctor_dtor_returns_void : Error< "%select{constructor|destructor}1 %0 must not return void expression">; def warn_noreturn_function_has_return_expr : Warning< "function %0 declared 'noreturn' should not return">, InGroup; def warn_falloff_noreturn_function : Warning< "function declared 'noreturn' should not return">, InGroup; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; def err_noreturn_missing_on_first_decl : Error< "function declared '[[noreturn]]' after its first declaration">; def note_noreturn_missing_first_decl : Note< "declaration missing '[[noreturn]]' attribute is here">; def err_carries_dependency_missing_on_first_decl : Error< "%select{function|parameter}0 declared '[[carries_dependency]]' " "after its first declaration">; def note_carries_dependency_missing_first_decl : Note< "declaration missing '[[carries_dependency]]' attribute is here">; def err_carries_dependency_param_not_function_decl : Error< "'[[carries_dependency]]' attribute only allowed on parameter in a function " "declaration or lambda">; def err_block_on_nonlocal : Error< "__block attribute not allowed, only allowed on local variables">; def err_block_on_vm : Error< "__block attribute not allowed on declaration with a variably modified type">; def err_shufflevector_non_vector : Error< "first two arguments to __builtin_shufflevector must be vectors">; def err_shufflevector_incompatible_vector : Error< "first two arguments to __builtin_shufflevector must have the same type">; def err_shufflevector_nonconstant_argument : Error< "index for __builtin_shufflevector must be a constant integer">; def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; def err_convertvector_non_vector_type : Error< "second argument to __builtin_convertvector must be a vector type">; def err_convertvector_incompatible_vector : Error< "first two arguments to __builtin_convertvector must have the same number of elements">; def err_first_argument_to_cwsc_not_call : Error< "first argument to __builtin_call_with_static_chain must be a non-member call expression">; def err_first_argument_to_cwsc_block_call : Error< "first argument to __builtin_call_with_static_chain must not be a block call">; def err_first_argument_to_cwsc_builtin_call : Error< "first argument to __builtin_call_with_static_chain must not be a builtin call">; def err_first_argument_to_cwsc_pdtor_call : Error< "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">; def err_second_argument_to_cwsc_not_pointer : Error< "second argument to __builtin_call_with_static_chain must be of pointer type">; def err_vector_incorrect_num_initializers : Error< "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; def err_altivec_empty_initializer : Error<"expected initializer">; def err_invalid_neon_type_code : Error< "incompatible constant for this __builtin_neon function">; def err_argument_invalid_range : Error< "argument should be a value from %0 to %1">; def warn_neon_vector_initializer_non_portable : Warning< "vector initializers are not compatible with NEON intrinsics in big endian " "mode">, InGroup>; def note_neon_vector_initializer_non_portable : Note< "consider using vld1_%0%1() to initialize a vector from memory, or " "vcreate_%0%1() to initialize from an integer constant">; def note_neon_vector_initializer_non_portable_q : Note< "consider using vld1q_%0%1() to initialize a vector from memory, or " "vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer " "constants">; def err_builtin_longjmp_invalid_val : Error< "argument to __builtin_longjmp must be a constant 1">; def err_builtin_requires_language : Error<"'%0' is only available in %1">; def err_constant_integer_arg_type : Error< "argument to %0 must be a constant integer">; def ext_mixed_decls_code : Extension< "ISO C90 forbids mixing declarations and code">, InGroup>; def err_non_local_variable_decl_in_for : Error< "declaration of non-local variable in 'for' loop">; def err_non_variable_decl_in_for : Error< "non-variable declaration in 'for' loop">; def err_toomany_element_decls : Error< "only one element declaration is allowed">; def err_selector_element_not_lvalue : Error< "selector element is not a valid lvalue">; def err_selector_element_type : Error< "selector element type %0 is not a valid object">; def err_selector_element_const_type : Error< "selector element of type %0 cannot be a constant l-value expression">; def err_collection_expr_type : Error< "the type %0 is not a pointer to a fast-enumerable object">; def warn_collection_expr_type : Warning< "collection expression type %0 may not respond to %1">; def err_invalid_conversion_between_ext_vectors : Error< "invalid conversion between ext-vector type %0 and %1">; def warn_duplicate_attribute_exact : Warning< "attribute %0 is already applied">, InGroup; def warn_duplicate_attribute : Warning< "attribute %0 is already applied with different parameters">, InGroup; def warn_sync_fetch_and_nand_semantics_change : Warning< "the semantics of this intrinsic changed with GCC " "version 4.4 - the newer semantics are provided here">, InGroup>; // Type def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; def warn_receiver_forward_class : Warning< "receiver %0 is a forward class and corresponding @interface may not exist">, InGroup; def note_method_sent_forward_class : Note<"method %0 is used for the forward class">; def ext_missing_declspec : ExtWarn< "declaration specifier missing, defaulting to 'int'">; def ext_missing_type_specifier : ExtWarn< "type specifier missing, defaults to 'int'">, InGroup; def err_decimal_unsupported : Error< "GNU decimal type extension not supported">; def err_missing_type_specifier : Error< "C++ requires a type specifier for all declarations">; def err_objc_array_of_interfaces : Error< "array of interface %0 is invalid (probably should be an array of pointers)">; def ext_c99_array_usage : Extension< "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " "feature">, InGroup; def err_c99_array_usage_cxx : Error< "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " "feature, not permitted in C++">; def err_double_requires_fp64 : Error< "use of type 'double' requires cl_khr_fp64 extension to be enabled">; def err_int128_unsupported : Error< "__int128 is not supported on this target">; def err_nsconsumed_attribute_mismatch : Error< "overriding method has mismatched ns_consumed attribute on its" " parameter">; def err_nsreturns_retained_attribute_mismatch : Error< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" " attributes">; def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; def err_invalid_protocol_qualifiers : Error< "invalid protocol qualifiers on non-ObjC type">; def warn_ivar_use_hidden : Warning< "local declaration of %0 hides instance variable">, InGroup>; def warn_direct_initialize_call : Warning< "explicit call to +initialize results in duplicate call to +initialize">, InGroup; def warn_direct_super_initialize_call : Warning< "explicit call to [super initialize] should only be in implementation " "of +initialize">, InGroup; def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; def error_implicit_ivar_access : Error< "instance variable %0 cannot be accessed because 'self' has been redeclared">; def error_private_ivar_access : Error<"instance variable %0 is private">, AccessControl; def error_protected_ivar_access : Error<"instance variable %0 is protected">, AccessControl; def warn_maynot_respond : Warning<"%0 may not respond to %1">; def ext_typecheck_base_super : Warning< "method parameter type " "%diff{$ does not match super class method parameter type $|" "does not match super class method parameter type}0,1">, InGroup, DefaultIgnore; def warn_missing_method_return_type : Warning< "method has no return type specified; defaults to 'id'">, InGroup, DefaultIgnore; def warn_direct_ivar_access : Warning<"instance variable %0 is being " "directly accessed">, InGroup>, DefaultIgnore; // Spell-checking diagnostics def err_unknown_typename : Error< "unknown type name %0">; def err_unknown_type_or_class_name_suggest : Error< "unknown %select{type|class}1 name %0; did you mean %2?">; def err_unknown_typename_suggest : Error< "unknown type name %0; did you mean %1?">; def err_unknown_nested_typename_suggest : Error< "no type named %0 in %1; did you mean %select{|simply }2%3?">; def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">; def err_undeclared_use_suggest : Error< "use of undeclared %0; did you mean %1?">; def err_undeclared_var_use_suggest : Error< "use of undeclared identifier %0; did you mean %1?">; def err_no_template_suggest : Error<"no template named %0; did you mean %1?">; def err_no_member_template_suggest : Error< "no template named %0 in %1; did you mean %select{|simply }2%3?">; def err_mem_init_not_member_or_class_suggest : Error< "initializer %0 does not name a non-static data member or base " "class; did you mean the %select{base class|member}1 %2?">; def err_field_designator_unknown_suggest : Error< "field designator %0 does not refer to any field in type %1; did you mean " "%2?">; def err_typecheck_member_reference_ivar_suggest : Error< "%0 does not have a member named %1; did you mean %2?">; def err_property_not_found_suggest : Error< "property %0 not found on object of type %1; did you mean %2?">; def err_ivar_access_using_property_syntax_suggest : Error< "property %0 not found on object of type %1; did you mean to access instance variable %2?">; def warn_property_access_suggest : Warning< "property %0 not found on object of type %1; did you mean to access property %2?">, InGroup; def err_property_found_suggest : Error< "property %0 found on object of type %1; did you mean to access " "it with the \".\" operator?">; def err_undef_interface_suggest : Error< "cannot find interface declaration for %0; did you mean %1?">; def warn_undef_interface_suggest : Warning< "cannot find interface declaration for %0; did you mean %1?">; def err_undef_superclass_suggest : Error< "cannot find interface declaration for %0, superclass of %1; did you mean " "%2?">; def err_undeclared_protocol_suggest : Error< "cannot find protocol declaration for %0; did you mean %1?">; def note_base_class_specified_here : Note< "base class %0 specified here">; def err_using_directive_suggest : Error< "no namespace named %0; did you mean %1?">; def err_using_directive_member_suggest : Error< "no namespace named %0 in %1; did you mean %select{|simply }2%3?">; def note_namespace_defined_here : Note<"namespace %0 defined here">; def err_sizeof_pack_no_pack_name_suggest : Error< "%0 does not refer to the name of a parameter pack; did you mean %1?">; def note_parameter_pack_here : Note<"parameter pack %0 declared here">; def err_uncasted_use_of_unknown_any : Error< "%0 has unknown type; cast it to its declared type to use it">; def err_uncasted_call_of_unknown_any : Error< "%0 has unknown return type; cast the call to its declared return type">; def err_uncasted_send_to_unknown_any_method : Error< "no known method %select{%objcinstance1|%objcclass1}0; cast the " "message send to the method's return type">; def err_unsupported_unknown_any_decl : Error< "%0 has unknown type, which is not supported for this kind of declaration">; def err_unsupported_unknown_any_expr : Error< "unsupported expression with unknown type">; def err_unsupported_unknown_any_call : Error< "call to unsupported expression with unknown type">; def err_unknown_any_addrof : Error< "the address of a declaration with unknown type " "can only be cast to a pointer type">; def err_unknown_any_var_function_type : Error< "variable %0 with unknown type cannot be given a function type">; def err_unknown_any_function : Error< "function %0 with unknown type must be given a function type">; def err_filter_expression_integral : Error< "filter expression type should be an integral value not %0">; def err_non_asm_stmt_in_naked_function : Error< "non-ASM statement in naked function is not supported">; def err_asm_naked_parm_ref : Error< "parameter references not allowed in naked functions">; // OpenCL warnings and errors. def err_invalid_astype_of_different_size : Error< "invalid reinterpretation: sizes of %0 and %1 must match">; def err_static_kernel : Error< "kernel functions cannot be declared static">; def err_opencl_ptrptr_kernel_param : Error< "kernel parameter cannot be declared as a pointer to a pointer">; def err_opencl_private_ptr_kernel_param : Error< "kernel parameter cannot be declared as a pointer to the __private address space">; def err_static_function_scope : Error< "variables in function scope cannot be declared static">; def err_opencl_bitfields : Error< "bitfields are not supported in OpenCL">; def err_opencl_vla : Error< "variable length arrays are not supported in OpenCL">; def err_bad_kernel_param_type : Error< "%0 cannot be used as the type of a kernel parameter">; def err_record_with_pointers_kernel_param : Error< "%select{struct|union}0 kernel parameters may not contain pointers">; def note_within_field_of_type : Note< "within field of type %0 declared here">; def note_illegal_field_declared_here : Note< "field of illegal %select{type|pointer type}0 %1 declared here">; def err_event_t_global_var : Error< "the event_t type cannot be used to declare a program scope variable">; def err_event_t_struct_field : Error< "the event_t type cannot be used to declare a structure or union field">; def err_event_t_addr_space_qual : Error< "the event_t type can only be used with __private address space qualifier">; def err_expected_kernel_void_return_type : Error< "kernel must have void return type">; def err_sampler_argument_required : Error< "sampler_t variable required - got %0">; def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; def err_opencl_global_invalid_addr_space : Error< "global variables must have a constant address space qualifier">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : Error<"attribute %0 can only be applied to a kernel function">; def err_opencl_return_value_with_address_space : Error< "return value cannot be qualified with address space">; def err_opencl_constant_no_init : Error< "variable in constant address space must be initialized">; } // end of sema category let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< "%0 is not a global variable, static local variable or static data member">; def err_omp_expected_var_arg_suggest : Error< "%0 is not a global variable, static local variable or static data member; " "did you mean %1">; def err_omp_global_var_arg : Error< "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">; def err_omp_ref_type_arg : Error< "arguments of '#pragma omp %0' cannot be of reference type %1">; def err_omp_var_scope : Error< "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">; def err_omp_var_used : Error< "'#pragma omp %0' must precede all references to variable %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is %select{thread-local|a global named register variable}1">; def err_omp_private_incomplete_type : Error< "a private variable with incomplete type %0">; def err_omp_firstprivate_incomplete_type : Error< "a firstprivate variable with incomplete type %0">; def err_omp_lastprivate_incomplete_type : Error< "a lastprivate variable with incomplete type %0">; def err_omp_reduction_incomplete_type : Error< "a reduction variable with incomplete type %0">; def err_omp_unexpected_clause_value : Error< "expected %0 in OpenMP clause '%1'">; def err_omp_expected_var_name : Error< "expected variable name">; def err_omp_required_method : Error< "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">; def note_omp_task_predetermined_firstprivate_here : Note< "predetermined as a firstprivate in a task construct here">; def err_omp_clause_ref_type_arg : Error< "arguments of OpenMP clause '%0' cannot be of reference type %1">; def err_omp_task_predetermined_firstprivate_ref_type_arg : Error< "predetermined as a firstprivate in a task construct variable cannot be of reference type %0">; def err_omp_threadprivate_incomplete_type : Error< "threadprivate variable with incomplete type %0">; def err_omp_no_dsa_for_variable : Error< "variable %0 must have explicitly specified data sharing attributes">; def err_omp_wrong_dsa : Error< "%0 variable cannot be %1">; def note_omp_explicit_dsa : Note< "defined as %0">; def note_omp_predetermined_dsa : Note< "%select{static data member is predetermined as shared|" "variable with static storage duration is predetermined as shared|" "loop iteration variable is predetermined as private|" "loop iteration variable is predetermined as linear|" "loop iteration variable is predetermined as lastprivate|" "constant variable is predetermined as shared|" "global variable is predetermined as shared|" "non-shared variable in a task construct is predetermined as firstprivate|" "variable with automatic storage duration is predetermined as private}0" "%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">; def note_omp_implicit_dsa : Note< "implicitly determined as %0">; def err_omp_loop_var_dsa : Error< "loop iteration variable in the associated loop of 'omp %1' directive may not be %0, predetermined as %2">; def err_omp_global_loop_var_dsa : Error< "loop iteration variable in the associated loop of 'omp %1' directive may not be a variable with global storage without being explicitly marked as %0">; def err_omp_not_for : Error< "%select{statement after '#pragma omp %1' must be a for loop|" "expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">; def note_omp_collapse_expr : Note< "as specified in 'collapse' clause">; def err_omp_negative_expression_in_clause : Error< "argument to '%0' clause must be a positive integer value">; def err_omp_not_integral : Error< "expression must have integral or unscoped enumeration " "type, not %0">; def err_omp_incomplete_type : Error< "expression has incomplete class type %0">; def err_omp_explicit_conversion : Error< "expression requires explicit conversion from %0 to %1">; def note_omp_conversion_here : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_omp_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; def err_omp_required_access : Error< "%0 variable must be %1">; def err_omp_const_variable : Error< "const-qualified variable cannot be %0">; def err_omp_linear_incomplete_type : Error< "a linear variable with incomplete type %0">; def err_omp_linear_expected_int_or_ptr : Error< "argument of a linear clause should be of integral or pointer " "type, not %0">; def warn_omp_linear_step_zero : Warning< "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">, InGroup; def warn_omp_alignment_not_power_of_two : Warning< "aligned clause will be ignored because the requested alignment is not a power of 2">, InGroup; def err_omp_aligned_expected_array_or_ptr : Error< "argument of aligned clause should be array" "%select{ or pointer|, pointer, reference to array or reference to pointer}1" ", not %0">; def err_omp_aligned_twice : Error< "a variable cannot appear in more than one aligned clause">; def err_omp_local_var_in_threadprivate_init : Error< "variable with local storage in initial value of threadprivate variable">; def err_omp_loop_not_canonical_init : Error< "initialization clause of OpenMP for loop must be of the form " "'var = init' or 'T var = init'">; def ext_omp_loop_not_canonical_init : ExtWarn< "initialization clause of OpenMP for loop is not in canonical form " "('var = init' or 'T var = init')">, InGroup; def err_omp_loop_not_canonical_cond : Error< "condition of OpenMP for loop must be a relational comparison " "('<', '<=', '>', or '>=') of loop variable %0">; def err_omp_loop_not_canonical_incr : Error< "increment clause of OpenMP for loop must perform simple addition " "or subtraction on loop variable %0">; def err_omp_loop_variable_type : Error< "variable must be of integer or %select{pointer|random access iterator}0 type">; def err_omp_loop_incr_not_compatible : Error< "increment expression must cause %0 to %select{decrease|increase}1 " "on each iteration of OpenMP for loop">; def note_omp_loop_cond_requres_compatible_incr : Note< "loop step is expected to be %select{negative|positive}0 due to this condition">; def err_omp_loop_diff_cxx : Error< "could not calculate number of iterations calling 'operator-' with " "upper and lower loop bounds">; def err_omp_loop_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP for loop">; def err_omp_simd_region_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP simd region">; def warn_omp_loop_64_bit_var : Warning< "OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed">, InGroup; def err_omp_unknown_reduction_identifier : Error< "incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'">; def err_omp_reduction_type_array : Error< "a reduction variable with array type %0">; def err_omp_reduction_ref_type_arg : Error< "argument of OpenMP clause 'reduction' must reference the same object in all threads">; def err_omp_clause_not_arithmetic_type_arg : Error< "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">; def err_omp_clause_floating_type_arg : Error< "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">; def err_omp_once_referenced : Error< "variable can appear only once in OpenMP '%0' clause">; def note_omp_referenced : Note< "previously referenced here">; def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< "variable of type %0 is not valid for specified reduction operation">; def err_omp_prohibited_region : Error< "region cannot be%select{| closely}0 nested inside '%1' region" "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|" "; perhaps you forget to enclose 'omp %3' directive into a target region?}2">; def err_omp_prohibited_region_simd : Error< "OpenMP constructs may not be nested inside a simd region">; def err_omp_prohibited_region_atomic : Error< "OpenMP constructs may not be nested inside an atomic region">; def err_omp_prohibited_region_critical_same_name : Error< "cannot nest 'critical' regions having the same name %0">; def note_omp_previous_critical_region : Note< "previous 'critical' region starts here">; def err_omp_sections_not_compound_stmt : Error< "the statement for '#pragma omp sections' must be a compound statement">; def err_omp_parallel_sections_not_compound_stmt : Error< "the statement for '#pragma omp parallel sections' must be a compound statement">; def err_omp_orphaned_section_directive : Error< "%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0" " must be closely nested to a sections region%select{|, not a %1 region}0">; def err_omp_sections_substmt_not_section : Error< "statement in 'omp sections' directive must be enclosed into a section region">; def err_omp_parallel_sections_substmt_not_section : Error< "statement in 'omp parallel sections' directive must be enclosed into a section region">; def err_omp_parallel_reduction_in_task_firstprivate : Error< "argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">; def err_omp_atomic_read_not_expression_statement : Error< "the statement for 'atomic read' must be an expression statement of form 'v = x;'," " where v and x are both lvalue expressions with scalar type">; def note_omp_atomic_read_write: Note< "%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">; def err_omp_atomic_write_not_expression_statement : Error< "the statement for 'atomic write' must be an expression statement of form 'x = expr;'," " where x is a lvalue expression with scalar type">; def err_omp_atomic_update_not_expression_statement : Error< "the statement for 'atomic%select{| update}0' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," " where x is an l-value expression with scalar type">; def err_omp_atomic_capture_not_expression_statement : Error< "the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x'," " where x and v are both l-value expressions with scalar type">; def err_omp_atomic_capture_not_compound_statement : Error< "the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}'," " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}'," " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'" " where x is an l-value expression with scalar type">; def err_omp_atomic_several_clauses : Error< "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">; def note_omp_atomic_previous_clause : Note< "'%0' clause used here">; def err_omp_target_contains_not_only_teams : Error< "target construct with nested teams region contains statements outside of the teams construct">; def note_omp_nested_teams_construct_here : Note< "nested teams construct here">; def note_omp_nested_statement_here : Note< "%select{statement|directive}0 outside teams construct here">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { // Objective-C related result type compatibility def warn_related_result_type_compatibility_class : Warning< "method is expected to return an instance of its class type " "%diff{$, but is declared to return $|" ", but is declared to return different type}0,1">; def warn_related_result_type_compatibility_protocol : Warning< "protocol method is expected to return an instance of the implementing " "class, but is declared to return %0">; def note_related_result_type_family : Note< "%select{overridden|current}0 method is part of the '%select{|alloc|copy|init|" "mutableCopy|new|autorelease|dealloc|finalize|release|retain|retainCount|" "self}1' method family%select{| and is expected to return an instance of its " "class type}0">; def note_related_result_type_overridden : Note< "overridden method returns an instance of its class type">; def note_related_result_type_inferred : Note< "%select{class|instance}0 method %1 is assumed to return an instance of " "its receiver type (%2)">; def note_related_result_type_explicit : Note< "%select{overridden|current}0 method is explicitly declared 'instancetype'" "%select{| and is expected to return an instance of its class type}0">; } let CategoryName = "Modules Issue" in { def err_module_private_specialization : Error< "%select{template|partial|member}0 specialization cannot be " "declared __module_private__">; def err_module_private_local : Error< "%select{local variable|parameter|typedef}0 %1 cannot be declared " "__module_private__">; def err_module_private_local_class : Error< "local %select{struct|interface|union|class|enum}0 cannot be declared " "__module_private__">; def err_module_private_declaration : Error< "declaration of %0 must be imported from module '%1' before it is required">; def err_module_private_definition : Error< "definition of %0 must be imported from module '%1' before it is required">; def err_module_import_in_extern_c : Error< "import of C++ module '%0' appears within extern \"C\" language linkage " "specification">; def note_module_import_in_extern_c : Note< "extern \"C\" language linkage specification begins here">; def err_module_import_not_at_top_level : Error< "import of module '%0' appears within %1">; def note_module_import_not_at_top_level : Note<"%0 begins here">; def err_module_self_import : Error< "import of module '%0' appears within same top-level module '%1'">; def err_module_import_in_implementation : Error< "@import of module '%0' in implementation of '%1'; use #import">; } let CategoryName = "Documentation Issue" in { def warn_not_a_doxygen_trailing_member_comment : Warning< "not a Doxygen trailing comment">, InGroup, DefaultIgnore; } // end of documentation issue category let CategoryName = "Instrumentation Issue" in { def warn_profile_data_out_of_date : Warning< "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, InGroup; def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup; } // end of instrumentation issue category } // end of sema component. Index: vendor/clang/dist/lib/AST/DeclCXX.cpp =================================================================== --- vendor/clang/dist/lib/AST/DeclCXX.cpp (revision 278753) +++ vendor/clang/dist/lib/AST/DeclCXX.cpp (revision 278754) @@ -1,2206 +1,2206 @@ //===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the C++ related Decl classes. // //===----------------------------------------------------------------------===// #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" using namespace clang; //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// void AccessSpecDecl::anchor() { } AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) AccessSpecDecl(EmptyShell()); } void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const { ExternalASTSource *Source = C.getExternalSource(); assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set"); assert(Source && "getFromExternalSource with no external source"); for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I) I.setDecl(cast(Source->GetExternalDecl( reinterpret_cast(I.getDecl()) >> 2))); Impl.Decls.setLazy(false); } CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true), HasInClassInitializer(false), HasUninitializedReferenceMember(false), NeedOverloadResolutionForMoveConstructor(false), NeedOverloadResolutionForMoveAssignment(false), NeedOverloadResolutionForDestructor(false), DefaultedMoveConstructorIsDeleted(false), DefaultedMoveAssignmentIsDeleted(false), DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), DefaultedDefaultConstructorIsConstexpr(true), HasConstexprDefaultConstructor(false), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0), ImplicitCopyConstructorHasConstParam(true), ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false), IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend() { } CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { return Bases.get(Definition->getASTContext().getExternalSource()); } CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getVBasesSlowCase() const { return VBases.get(Definition->getASTContext().getExternalSource()); } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl) : RecordDecl(K, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl), DefinitionData(PrevDecl ? PrevDecl->DefinitionData : DefinitionDataPtr(this)), TemplateOrInstantiation() {} CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl* PrevDecl, bool DelayTypeCreation) { CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); R->MayHaveOutOfDateDef = C.getLangOpts().Modules; // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) C.getTypeDeclType(R, PrevDecl); return R; } CXXRecordDecl * CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, bool Dependent, bool IsGeneric, LambdaCaptureDefault CaptureDefault) { CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc, nullptr, nullptr); R->IsBeingDefined = true; R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent, IsGeneric, CaptureDefault); R->MayHaveOutOfDateDef = false; R->setImplicit(true); C.getTypeDeclType(R, /*PrevDecl=*/nullptr); return R; } CXXRecordDecl * CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { CXXRecordDecl *R = new (C, ID) CXXRecordDecl( CXXRecord, TTK_Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); R->MayHaveOutOfDateDef = false; return R; } void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { ASTContext &C = getASTContext(); if (!data().Bases.isOffset() && data().NumBases > 0) C.Deallocate(data().getBases()); if (NumBases) { // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. data().Aggregate = false; // C++ [class]p4: // A POD-struct is an aggregate class... data().PlainOldData = false; } // The set of seen virtual base types. llvm::SmallPtrSet SeenVBaseTypes; // The virtual bases of this class. SmallVector VBases; data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { data().getBases()[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); // A class with a non-empty base class is not empty. // FIXME: Standard ref? if (!BaseClassDecl->isEmpty()) { if (!data().Empty) { // C++0x [class]p7: // A standard-layout class is a class that: // [...] // -- either has no non-static data members in the most derived // class and at most one base class with non-static data members, // or has no base classes with non-static data members, and // If this is the second non-empty base, then neither of these two // clauses can be true. data().IsStandardLayout = false; } data().Empty = false; data().HasNoNonEmptyBases = false; } // C++ [class.virtual]p1: // A class that declares or inherits a virtual function is called a // polymorphic class. if (BaseClassDecl->isPolymorphic()) data().Polymorphic = true; // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no non-standard-layout base classes if (!BaseClassDecl->isStandardLayout()) data().IsStandardLayout = false; // Record if this base is the first non-literal field or base. if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C)) data().HasNonLiteralTypeFieldsOrBases = true; // Now go through all virtual bases of this base and add them. for (const auto &VBase : BaseClassDecl->vbases()) { // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType())).second) { VBases.push_back(&VBase); // C++11 [class.copy]p8: // The implicitly-declared copy constructor for a class X will have // the form 'X::X(const X&)' if each [...] virtual base class B of X // has a copy constructor whose first parameter is of type // 'const B&' or 'const volatile B&' [...] if (CXXRecordDecl *VBaseDecl = VBase.getType()->getAsCXXRecordDecl()) if (!VBaseDecl->hasCopyConstructorWithConstParam()) data().ImplicitCopyConstructorHasConstParam = false; } } if (Base->isVirtual()) { // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)).second) VBases.push_back(Base); // C++0x [meta.unary.prop] is_empty: // T is a class type, but not a union type, with ... no virtual base // classes data().Empty = false; // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: // A [default constructor, copy/move constructor, or copy/move assignment // operator for a class X] is trivial [...] if: // -- class X has [...] no virtual base classes data().HasTrivialSpecialMembers &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has [...] no virtual base classes data().IsStandardLayout = false; // C++11 [dcl.constexpr]p4: // In the definition of a constexpr constructor [...] // -- the class shall not have any virtual base classes data().DefaultedDefaultConstructorIsConstexpr = false; } else { // C++ [class.ctor]p5: // A default constructor is trivial [...] if: // -- all the direct base classes of its class have trivial default // constructors. if (!BaseClassDecl->hasTrivialDefaultConstructor()) data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] // [...] // -- the constructor selected to copy/move each direct base class // subobject is trivial, and if (!BaseClassDecl->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; // If the base class doesn't have a simple move constructor, we'll eagerly // declare it and perform overload resolution to determine which function // it actually calls. If it does have a simple move constructor, this // check is correct. if (!BaseClassDecl->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] // [...] // -- the assignment operator selected to copy/move each direct base // class subobject is trivial, and if (!BaseClassDecl->hasTrivialCopyAssignment()) data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; // If the base class doesn't have a simple move assignment, we'll eagerly // declare it and perform overload resolution to determine which function // it actually calls. If it does have a simple move assignment, this // check is correct. if (!BaseClassDecl->hasTrivialMoveAssignment()) data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; // C++11 [class.ctor]p6: // If that user-written default constructor would satisfy the // requirements of a constexpr constructor, the implicitly-defined // default constructor is constexpr. if (!BaseClassDecl->hasConstexprDefaultConstructor()) data().DefaultedDefaultConstructorIsConstexpr = false; } // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!BaseClassDecl->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; // C++11 [class.copy]p18: // The implicitly-declared copy assignment oeprator for a class X will // have the form 'X& X::operator=(const X&)' if each direct base class B // of X has a copy assignment operator whose parameter is of type 'const // B&', 'const volatile B&', or 'B' [...] if (!BaseClassDecl->hasCopyAssignmentWithConstParam()) data().ImplicitCopyAssignmentHasConstParam = false; // C++11 [class.copy]p8: // The implicitly-declared copy constructor for a class X will have // the form 'X::X(const X&)' if each direct [...] base class B of X // has a copy constructor whose first parameter is of type // 'const B&' or 'const volatile B&' [...] if (!BaseClassDecl->hasCopyConstructorWithConstParam()) data().ImplicitCopyConstructorHasConstParam = false; // A class has an Objective-C object member if... or any of its bases // has an Objective-C object member. if (BaseClassDecl->hasObjectMember()) setHasObjectMember(true); if (BaseClassDecl->hasVolatileMember()) setHasVolatileMember(true); // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) data().HasMutableFields = true; if (BaseClassDecl->hasUninitializedReferenceMember()) data().HasUninitializedReferenceMember = true; addedClassSubobject(BaseClassDecl); } if (VBases.empty()) { data().IsParsingBaseSpecifiers = false; return; } // Create base specifier for any direct or indirect virtual bases. data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); for (int I = 0, E = VBases.size(); I != E; ++I) { QualType Type = VBases[I]->getType(); if (!Type->isDependentType()) addedClassSubobject(Type->getAsCXXRecordDecl()); data().getVBases()[I] = *VBases[I]; } data().IsParsingBaseSpecifiers = false; } void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) { // C++11 [class.copy]p11: // A defaulted copy/move constructor for a class X is defined as // deleted if X has: // -- a direct or virtual base class B that cannot be copied/moved [...] // -- a non-static data member of class type M (or array thereof) // that cannot be copied or moved [...] if (!Subobj->hasSimpleMoveConstructor()) data().NeedOverloadResolutionForMoveConstructor = true; // C++11 [class.copy]p23: // A defaulted copy/move assignment operator for a class X is defined as // deleted if X has: // -- a direct or virtual base class B that cannot be copied/moved [...] // -- a non-static data member of class type M (or array thereof) // that cannot be copied or moved [...] if (!Subobj->hasSimpleMoveAssignment()) data().NeedOverloadResolutionForMoveAssignment = true; // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5: // A defaulted [ctor or dtor] for a class X is defined as // deleted if X has: // -- any direct or virtual base class [...] has a type with a destructor // that is deleted or inaccessible from the defaulted [ctor or dtor]. // -- any non-static data member has a type with a destructor // that is deleted or inaccessible from the defaulted [ctor or dtor]. if (!Subobj->hasSimpleDestructor()) { data().NeedOverloadResolutionForMoveConstructor = true; data().NeedOverloadResolutionForDestructor = true; } } /// Callback function for CXXRecordDecl::forallBases that acknowledges /// that it saw a base class. static bool SawBase(const CXXRecordDecl *, void *) { return true; } bool CXXRecordDecl::hasAnyDependentBases() const { if (!isDependentContext()) return false; return !forallBases(SawBase, nullptr); } bool CXXRecordDecl::isTriviallyCopyable() const { // C++0x [class]p5: // A trivially copyable class is a class that: // -- has no non-trivial copy constructors, if (hasNonTrivialCopyConstructor()) return false; // -- has no non-trivial move constructors, if (hasNonTrivialMoveConstructor()) return false; // -- has no non-trivial copy assignment operators, if (hasNonTrivialCopyAssignment()) return false; // -- has no non-trivial move assignment operators, and if (hasNonTrivialMoveAssignment()) return false; // -- has a trivial destructor. if (!hasTrivialDestructor()) return false; return true; } void CXXRecordDecl::markedVirtualFunctionPure() { // C++ [class.abstract]p2: // A class is abstract if it has at least one pure virtual function. data().Abstract = true; } void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa(D) && !isa(D) && (!isa(D) || cast(D)->getTagKind() == TTK_Class || cast(D)->getTagKind() == TTK_Interface)) data().HasOnlyCMembers = false; // Ignore friends and invalid declarations. if (D->getFriendObjectKind() || D->isInvalidDecl()) return; FunctionTemplateDecl *FunTmpl = dyn_cast(D); if (FunTmpl) D = FunTmpl->getTemplatedDecl(); if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isVirtual()) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with [...] no virtual functions. data().Aggregate = false; // C++ [class]p4: // A POD-struct is an aggregate class... data().PlainOldData = false; // Virtual functions make the class non-empty. // FIXME: Standard ref? data().Empty = false; // C++ [class.virtual]p1: // A class that declares or inherits a virtual function is called a // polymorphic class. data().Polymorphic = true; // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: // A [default constructor, copy/move constructor, or copy/move // assignment operator for a class X] is trivial [...] if: // -- class X has no virtual functions [...] data().HasTrivialSpecialMembers &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no virtual functions data().IsStandardLayout = false; } } // Notify the listener if an implicit member was added after the definition // was completed. if (!isBeingDefined() && D->isImplicit()) if (ASTMutationListener *L = getASTMutationListener()) L->AddedCXXImplicitMember(data().Definition, D); // The kind of special member this declaration is, if any. unsigned SMKind = 0; // Handle constructors. if (CXXConstructorDecl *Constructor = dyn_cast(D)) { if (!Constructor->isImplicit()) { // Note that we have a user-declared constructor. data().UserDeclaredConstructor = true; // C++ [class]p4: // A POD-struct is an aggregate class [...] // Since the POD bit is meant to be C++03 POD-ness, clear it even if the // type is technically an aggregate in C++0x since it wouldn't be in 03. data().PlainOldData = false; } // Technically, "user-provided" is only defined for special member // functions, but the intent of the standard is clearly that it should apply // to all functions. bool UserProvided = Constructor->isUserProvided(); if (Constructor->isDefaultConstructor()) { SMKind |= SMF_DefaultConstructor; if (UserProvided) data().UserProvidedDefaultConstructor = true; if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; } if (!FunTmpl) { unsigned Quals; if (Constructor->isCopyConstructor(Quals)) { SMKind |= SMF_CopyConstructor; if (Quals & Qualifiers::Const) data().HasDeclaredCopyConstructorWithConstParam = true; } else if (Constructor->isMoveConstructor()) SMKind |= SMF_MoveConstructor; } // Record if we see any constexpr constructors which are neither copy // nor move constructors. if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) data().HasConstexprNonCopyMoveConstructor = true; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-declared // constructors [...]. // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. if (getASTContext().getLangOpts().CPlusPlus11 ? UserProvided : !Constructor->isImplicit()) data().Aggregate = false; } // Handle destructors. if (CXXDestructorDecl *DD = dyn_cast(D)) { SMKind |= SMF_Destructor; if (DD->isUserProvided()) data().HasIrrelevantDestructor = false; // If the destructor is explicitly defaulted and not trivial or not public // or if the destructor is deleted, we clear HasIrrelevantDestructor in // finishedDefaultedOrDeletedMember. // C++11 [class.dtor]p5: // A destructor is trivial if [...] the destructor is not virtual. if (DD->isVirtual()) data().HasTrivialSpecialMembers &= ~SMF_Destructor; } // Handle member functions. if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isCopyAssignmentOperator()) { SMKind |= SMF_CopyAssignment; const ReferenceType *ParamTy = Method->getParamDecl(0)->getType()->getAs(); if (!ParamTy || ParamTy->getPointeeType().isConstQualified()) data().HasDeclaredCopyAssignmentWithConstParam = true; } if (Method->isMoveAssignmentOperator()) SMKind |= SMF_MoveAssignment; // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast(D)) { // FIXME: We use the 'unsafe' accessor for the access specifier here, // because Sema may not have set it yet. That's really just a misdesign // in Sema. However, LLDB *will* have set the access specifier correctly, // and adds declarations after the class is technically completed, // so completeDefinition()'s overriding of the access specifiers doesn't // work. AccessSpecifier AS = Conversion->getAccessUnsafe(); if (Conversion->getPrimaryTemplate()) { // We don't record specializations. } else { ASTContext &Ctx = getASTContext(); ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx); NamedDecl *Primary = FunTmpl ? cast(FunTmpl) : cast(Conversion); if (Primary->getPreviousDecl()) Conversions.replace(cast(Primary->getPreviousDecl()), Primary, AS); else Conversions.addDecl(Ctx, Primary, AS); } } if (SMKind) { // If this is the first declaration of a special member, we no longer have // an implicit trivial special member. data().HasTrivialSpecialMembers &= data().DeclaredSpecialMembers | ~SMKind; if (!Method->isImplicit() && !Method->isUserProvided()) { // This method is user-declared but not user-provided. We can't work out // whether it's trivial yet (not until we get to the end of the class). // We'll handle this method in finishedDefaultedOrDeletedMember. } else if (Method->isTrivial()) data().HasTrivialSpecialMembers |= SMKind; else data().DeclaredNonTrivialSpecialMembers |= SMKind; // Note when we have declared a declared special member, and suppress the // implicit declaration of this special member. data().DeclaredSpecialMembers |= SMKind; if (!Method->isImplicit()) { data().UserDeclaredSpecialMembers |= SMKind; // C++03 [class]p4: // A POD-struct is an aggregate class that has [...] no user-defined // copy assignment operator and no user-defined destructor. // // Since the POD bit is meant to be C++03 POD-ness, and in C++03, // aggregates could not have any constructors, clear it even for an // explicitly defaulted or deleted constructor. // type is technically an aggregate in C++0x since it wouldn't be in 03. // // Also, a user-declared move assignment operator makes a class non-POD. // This is an extension in C++03. data().PlainOldData = false; } } return; } // Handle non-static data members. if (FieldDecl *Field = dyn_cast(D)) { // C++ [class.bit]p2: // A declaration for a bit-field that omits the identifier declares an // unnamed bit-field. Unnamed bit-fields are not members and cannot be // initialized. if (Field->isUnnamedBitfield()) return; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] no // private or protected non-static data members (clause 11). // // A POD must be an aggregate. if (D->getAccess() == AS_private || D->getAccess() == AS_protected) { data().Aggregate = false; data().PlainOldData = false; } // C++0x [class]p7: // A standard-layout class is a class that: // [...] // -- has the same access control for all non-static data members, switch (D->getAccess()) { case AS_private: data().HasPrivateFields = true; break; case AS_protected: data().HasProtectedFields = true; break; case AS_public: data().HasPublicFields = true; break; case AS_none: llvm_unreachable("Invalid access specifier"); }; if ((data().HasPrivateFields + data().HasProtectedFields + data().HasPublicFields) > 1) data().IsStandardLayout = false; // Keep track of the presence of mutable fields. if (Field->isMutable()) data().HasMutableFields = true; // C++11 [class.union]p8, DR1460: // If X is a union, a non-static data member of X that is not an anonymous // union is a variant member of X. if (isUnion() && !Field->isAnonymousStructOrUnion()) data().HasVariantMembers = true; // C++0x [class]p9: // A POD struct is a class that is both a trivial class and a // standard-layout class, and has no non-static data members of type // non-POD struct, non-POD union (or array of such types). // // Automatic Reference Counting: the presence of a member of Objective-C pointer type // that does not explicitly have no lifetime makes the class a non-POD. ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); if (T->isObjCRetainableType() || T.isObjCGCStrong()) { if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { // Objective-C Automatic Reference Counting: // If a class has a non-static data member of Objective-C pointer // type (or array thereof), it is a non-POD type and its // default constructor (if any), copy constructor, move constructor, // copy assignment operator, move assignment operator, and destructor are // non-trivial. setHasObjectMember(true); struct DefinitionData &Data = data(); Data.PlainOldData = false; Data.HasTrivialSpecialMembers = 0; Data.HasIrrelevantDestructor = false; } } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; if (T->isReferenceType()) { if (!Field->hasInClassInitializer()) data().HasUninitializedReferenceMember = true; // C++0x [class]p7: // A standard-layout class is a class that: // -- has no non-static data members of type [...] reference, data().IsStandardLayout = false; } // Record if this field is the first non-literal or volatile field or base. if (!T->isLiteralType(Context) || T.isVolatileQualified()) data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer() || (Field->isAnonymousStructOrUnion() && Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) { data().HasInClassInitializer = true; // C++11 [class]p5: // A default constructor is trivial if [...] no non-static data member // of its class has a brace-or-equal-initializer. data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no // brace-or-equal-initializers for non-static data members. // // This rule was removed in C++1y. if (!getASTContext().getLangOpts().CPlusPlus14) data().Aggregate = false; // C++11 [class]p10: // A POD struct is [...] a trivial class. data().PlainOldData = false; } // C++11 [class.copy]p23: // A defaulted copy/move assignment operator for a class X is defined // as deleted if X has: // -- a non-static data member of reference type if (T->isReferenceType()) data().DefaultedMoveAssignmentIsDeleted = true; if (const RecordType *RecordTy = T->getAs()) { CXXRecordDecl* FieldRec = cast(RecordTy->getDecl()); if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); // We may need to perform overload resolution to determine whether a // field can be moved if it's const or volatile qualified. if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) { data().NeedOverloadResolutionForMoveConstructor = true; data().NeedOverloadResolutionForMoveAssignment = true; } // C++11 [class.ctor]p5, C++11 [class.copy]p11: // A defaulted [special member] for a class X is defined as // deleted if: // -- X is a union-like class that has a variant member with a // non-trivial [corresponding special member] if (isUnion()) { if (FieldRec->hasNonTrivialMoveConstructor()) data().DefaultedMoveConstructorIsDeleted = true; if (FieldRec->hasNonTrivialMoveAssignment()) data().DefaultedMoveAssignmentIsDeleted = true; if (FieldRec->hasNonTrivialDestructor()) data().DefaultedDestructorIsDeleted = true; } // C++0x [class.ctor]p5: // A default constructor is trivial [...] if: // -- for all the non-static data members of its class that are of // class type (or array thereof), each such class has a trivial // default constructor. if (!FieldRec->hasTrivialDefaultConstructor()) data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor; // C++0x [class.copy]p13: // A copy/move constructor for class X is trivial if [...] // [...] // -- for each non-static data member of X that is of class type (or // an array thereof), the constructor selected to copy/move that // member is trivial; if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; // If the field doesn't have a simple move constructor, we'll eagerly // declare the move constructor for this class and we'll decide whether // it's trivial then. if (!FieldRec->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] // [...] // -- for each non-static data member of X that is of class type (or // an array thereof), the assignment operator selected to // copy/move that member is trivial; if (!FieldRec->hasTrivialCopyAssignment()) data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment; // If the field doesn't have a simple move assignment, we'll eagerly // declare the move assignment for this class and we'll decide whether // it's trivial then. if (!FieldRec->hasTrivialMoveAssignment()) data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment; if (!FieldRec->hasTrivialDestructor()) data().HasTrivialSpecialMembers &= ~SMF_Destructor; if (!FieldRec->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) setHasObjectMember(true); if (FieldRec->hasVolatileMember()) setHasVolatileMember(true); // C++0x [class]p7: // A standard-layout class is a class that: // -- has no non-static data members of type non-standard-layout // class (or array of such types) [...] if (!FieldRec->isStandardLayout()) data().IsStandardLayout = false; // C++0x [class]p7: // A standard-layout class is a class that: // [...] // -- has no base classes of the same type as the first non-static // data member. // We don't want to expend bits in the state of the record decl // tracking whether this is the first non-static data member so we // cheat a bit and use some of the existing state: the empty bit. // Virtual bases and virtual methods make a class non-empty, but they // also make it non-standard-layout so we needn't check here. // A non-empty base class may leave the class standard-layout, but not // if we have arrived here, and have at least one non-static data // member. If IsStandardLayout remains true, then the first non-static // data member must come through here with Empty still true, and Empty // will subsequently be set to false below. if (data().IsStandardLayout && data().Empty) { for (const auto &BI : bases()) { if (Context.hasSameUnqualifiedType(BI.getType(), T)) { data().IsStandardLayout = false; break; } } } // Keep track of the presence of mutable fields. if (FieldRec->hasMutableFields()) data().HasMutableFields = true; // C++11 [class.copy]p13: // If the implicitly-defined constructor would satisfy the // requirements of a constexpr constructor, the implicitly-defined // constructor is constexpr. // C++11 [dcl.constexpr]p4: // -- every constructor involved in initializing non-static data // members [...] shall be a constexpr constructor if (!Field->hasInClassInitializer() && !FieldRec->hasConstexprDefaultConstructor() && !isUnion()) // The standard requires any in-class initializer to be a constant // expression. We consider this to be a defect. data().DefaultedDefaultConstructorIsConstexpr = false; // C++11 [class.copy]p8: // The implicitly-declared copy constructor for a class X will have // the form 'X::X(const X&)' if [...] for all the non-static data // members of X that are of a class type M (or array thereof), each // such class type has a copy constructor whose first parameter is // of type 'const M&' or 'const volatile M&'. if (!FieldRec->hasCopyConstructorWithConstParam()) data().ImplicitCopyConstructorHasConstParam = false; // C++11 [class.copy]p18: // The implicitly-declared copy assignment oeprator for a class X will // have the form 'X& X::operator=(const X&)' if [...] for all the // non-static data members of X that are of a class type M (or array // thereof), each such class type has a copy assignment operator whose // parameter is of type 'const M&', 'const volatile M&' or 'M'. if (!FieldRec->hasCopyAssignmentWithConstParam()) data().ImplicitCopyAssignmentHasConstParam = false; if (FieldRec->hasUninitializedReferenceMember() && !Field->hasInClassInitializer()) data().HasUninitializedReferenceMember = true; // C++11 [class.union]p8, DR1460: // a non-static data member of an anonymous union that is a member of // X is also a variant member of X. if (FieldRec->hasVariantMembers() && Field->isAnonymousStructOrUnion()) data().HasVariantMembers = true; } } else { // Base element type of field is a non-class type. if (!T->isLiteralType(Context) || (!Field->hasInClassInitializer() && !isUnion())) data().DefaultedDefaultConstructorIsConstexpr = false; // C++11 [class.copy]p23: // A defaulted copy/move assignment operator for a class X is defined // as deleted if X has: // -- a non-static data member of const non-class type (or array // thereof) if (T.isConstQualified()) data().DefaultedMoveAssignmentIsDeleted = true; } // C++0x [class]p7: // A standard-layout class is a class that: // [...] // -- either has no non-static data members in the most derived // class and at most one base class with non-static data members, // or has no base classes with non-static data members, and // At this point we know that we have a non-static data member, so the last // clause holds. if (!data().HasNoNonEmptyBases) data().IsStandardLayout = false; // If this is not a zero-length bit-field, then the class is not empty. if (data().Empty) { if (!Field->isBitField() || (!Field->getBitWidth()->isTypeDependent() && !Field->getBitWidth()->isValueDependent() && Field->getBitWidthValue(Context) != 0)) data().Empty = false; } } // Handle using declarations of conversion functions. if (UsingShadowDecl *Shadow = dyn_cast(D)) { if (Shadow->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) { ASTContext &Ctx = getASTContext(); data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess()); } } } void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { assert(!D->isImplicit() && !D->isUserProvided()); // The kind of special member this declaration is, if any. unsigned SMKind = 0; if (CXXConstructorDecl *Constructor = dyn_cast(D)) { if (Constructor->isDefaultConstructor()) { SMKind |= SMF_DefaultConstructor; if (Constructor->isConstexpr()) data().HasConstexprDefaultConstructor = true; } if (Constructor->isCopyConstructor()) SMKind |= SMF_CopyConstructor; else if (Constructor->isMoveConstructor()) SMKind |= SMF_MoveConstructor; else if (Constructor->isConstexpr()) // We may now know that the constructor is constexpr. data().HasConstexprNonCopyMoveConstructor = true; } else if (isa(D)) { SMKind |= SMF_Destructor; if (!D->isTrivial() || D->getAccess() != AS_public || D->isDeleted()) data().HasIrrelevantDestructor = false; } else if (D->isCopyAssignmentOperator()) SMKind |= SMF_CopyAssignment; else if (D->isMoveAssignmentOperator()) SMKind |= SMF_MoveAssignment; // Update which trivial / non-trivial special members we have. // addedMember will have skipped this step for this member. if (D->isTrivial()) data().HasTrivialSpecialMembers |= SMKind; else data().DeclaredNonTrivialSpecialMembers |= SMKind; } bool CXXRecordDecl::isCLike() const { if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || !TemplateOrInstantiation.isNull()) return false; if (!hasDefinition()) return true; return isPOD() && data().HasOnlyCMembers; } bool CXXRecordDecl::isGenericLambda() const { if (!isLambda()) return false; return getLambdaData().IsGenericLambda; } CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { if (!isLambda()) return nullptr; DeclarationName Name = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); DeclContext::lookup_const_result Calls = lookup(Name); assert(!Calls.empty() && "Missing lambda call operator!"); assert(Calls.size() == 1 && "More than one lambda call operator!"); NamedDecl *CallOp = Calls.front(); if (FunctionTemplateDecl *CallOpTmpl = dyn_cast(CallOp)) return cast(CallOpTmpl->getTemplatedDecl()); return cast(CallOp); } CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { if (!isLambda()) return nullptr; DeclarationName Name = &getASTContext().Idents.get(getLambdaStaticInvokerName()); DeclContext::lookup_const_result Invoker = lookup(Name); if (Invoker.empty()) return nullptr; assert(Invoker.size() == 1 && "More than one static invoker operator!"); NamedDecl *InvokerFun = Invoker.front(); if (FunctionTemplateDecl *InvokerTemplate = dyn_cast(InvokerFun)) return cast(InvokerTemplate->getTemplatedDecl()); return cast(InvokerFun); } void CXXRecordDecl::getCaptureFields( llvm::DenseMap &Captures, FieldDecl *&ThisCapture) const { Captures.clear(); ThisCapture = nullptr; LambdaDefinitionData &Lambda = getLambdaData(); RecordDecl::field_iterator Field = field_begin(); for (const LambdaCapture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures; C != CEnd; ++C, ++Field) { if (C->capturesThis()) ThisCapture = *Field; else if (C->capturesVariable()) Captures[C->getCapturedVar()] = *Field; } assert(Field == field_end()); } TemplateParameterList * CXXRecordDecl::getGenericLambdaTemplateParameterList() const { if (!isLambda()) return nullptr; CXXMethodDecl *CallOp = getLambdaCallOperator(); if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) return Tmpl->getTemplateParameters(); return nullptr; } static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T = cast(Conv->getUnderlyingDecl()->getAsFunction()) ->getConversionType(); return Context.getCanonicalType(T); } /// Collect the visible conversions of a base class. /// /// \param Record a base class of the class we're considering /// \param InVirtual whether this base class is a virtual base (or a base /// of a virtual base) /// \param Access the access along the inheritance path to this base /// \param ParentHiddenTypes the conversions provided by the inheritors /// of this base /// \param Output the set to which to add conversions from non-virtual bases /// \param VOutput the set to which to add conversions from virtual bases /// \param HiddenVBaseCs the set of conversions which were hidden in a /// virtual base along some inheritance path static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, bool InVirtual, AccessSpecifier Access, const llvm::SmallPtrSet &ParentHiddenTypes, ASTUnresolvedSet &Output, UnresolvedSetImpl &VOutput, llvm::SmallPtrSet &HiddenVBaseCs) { // The set of types which have conversions in this class or its // subclasses. As an optimization, we don't copy the derived set // unless it might change. const llvm::SmallPtrSet *HiddenTypes = &ParentHiddenTypes; llvm::SmallPtrSet HiddenTypesBuffer; // Collect the direct conversions and figure out which conversions // will be hidden in the subclasses. CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin(); CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end(); if (ConvI != ConvE) { HiddenTypesBuffer = ParentHiddenTypes; HiddenTypes = &HiddenTypesBuffer; for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) { CanQualType ConvType(GetConversionType(Context, I.getDecl())); bool Hidden = ParentHiddenTypes.count(ConvType); if (!Hidden) HiddenTypesBuffer.insert(ConvType); // If this conversion is hidden and we're in a virtual base, // remember that it's hidden along some inheritance path. if (Hidden && InVirtual) HiddenVBaseCs.insert(cast(I.getDecl()->getCanonicalDecl())); // If this conversion isn't hidden, add it to the appropriate output. else if (!Hidden) { AccessSpecifier IAccess = CXXRecordDecl::MergeAccess(Access, I.getAccess()); if (InVirtual) VOutput.addDecl(I.getDecl(), IAccess); else Output.addDecl(Context, I.getDecl(), IAccess); } } } // Collect information recursively from any base classes. for (const auto &I : Record->bases()) { const RecordType *RT = I.getType()->getAs(); if (!RT) continue; AccessSpecifier BaseAccess = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); CXXRecordDecl *Base = cast(RT->getDecl()); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } } /// Collect the visible conversions of a class. /// /// This would be extremely straightforward if it weren't for virtual /// bases. It might be worth special-casing that, really. static void CollectVisibleConversions(ASTContext &Context, CXXRecordDecl *Record, ASTUnresolvedSet &Output) { // The collection of all conversions in virtual bases that we've // found. These will be added to the output as long as they don't // appear in the hidden-conversions set. UnresolvedSet<8> VBaseCs; // The set of conversions in virtual bases that we've determined to // be hidden. llvm::SmallPtrSet HiddenVBaseCs; // The set of types hidden by classes derived from this one. llvm::SmallPtrSet HiddenTypes; // Go ahead and collect the direct conversions and add them to the // hidden-types set. CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin(); CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end(); Output.append(Context, ConvI, ConvE); for (; ConvI != ConvE; ++ConvI) HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl())); // Recursively collect conversions from base classes. for (const auto &I : Record->bases()) { const RecordType *RT = I.getType()->getAs(); if (!RT) continue; CollectVisibleConversions(Context, cast(RT->getDecl()), I.isVirtual(), I.getAccessSpecifier(), HiddenTypes, Output, VBaseCs, HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end(); I != E; ++I) { if (!HiddenVBaseCs.count(cast(I.getDecl()->getCanonicalDecl()))) Output.addDecl(Context, I.getDecl(), I.getAccess()); } } /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. std::pair CXXRecordDecl::getVisibleConversionFunctions() { ASTContext &Ctx = getASTContext(); ASTUnresolvedSet *Set; if (bases_begin() == bases_end()) { // If root class, all conversions are visible. Set = &data().Conversions.get(Ctx); } else { Set = &data().VisibleConversions.get(Ctx); // If visible conversion list is not evaluated, evaluate it. if (!data().ComputedVisibleConversions) { CollectVisibleConversions(Ctx, this, *Set); data().ComputedVisibleConversions = true; } } return std::make_pair(Set->begin(), Set->end()); } void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { // This operation is O(N) but extremely rare. Sema only uses it to // remove UsingShadowDecls in a class that were followed by a direct // declaration, e.g.: // class A : B { // using B::operator int; // operator int(); // }; // This is uncommon by itself and even more uncommon in conjunction // with sufficiently large numbers of directly-declared conversions // that asymptotic behavior matters. ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext()); for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end() && "conversion was found multiple times in unresolved set"); return; } } llvm_unreachable("conversion not found in set!"); } CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return cast(MSInfo->getInstantiatedFrom()); return nullptr; } void CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, TemplateSpecializationKind TSK) { assert(TemplateOrInstantiation.isNull() && "Previous template or instantiation?"); assert(!isa(this)); TemplateOrInstantiation = new (getASTContext()) MemberSpecializationInfo(RD, TSK); } TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(this)) return Spec->getSpecializationKind(); if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; } void CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast(this)) { Spec->setSpecializationKind(TSK); return; } if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); return; } llvm_unreachable("Not a class template or member class specialization"); } const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { // If it's a class template specialization, find the template or partial // specialization from which it was instantiated. if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { if (NewCTD->isMemberSpecialization()) break; CTD = NewCTD; } return CTD->getTemplatedDecl(); } if (auto *CTPSD = From.dyn_cast()) { while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { if (NewCTPSD->isMemberSpecialization()) break; CTPSD = NewCTPSD; } return CTPSD; } } if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { const CXXRecordDecl *RD = this; while (auto *NewRD = RD->getInstantiatedFromMemberClass()) RD = NewRD; return RD; } } assert(!isTemplateInstantiation(this->getTemplateSpecializationKind()) && "couldn't find pattern for class template instantiation"); return nullptr; } CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(this); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); DeclContext::lookup_const_result R = lookup(Name); if (R.empty()) return nullptr; CXXDestructorDecl *Dtor = cast(R.front()); return Dtor; } void CXXRecordDecl::completeDefinition() { completeDefinition(nullptr); } void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { RecordDecl::completeDefinition(); // If the class may be abstract (but hasn't been marked as such), check for // any pure final overriders. if (mayBeAbstract()) { CXXFinalOverriderMap MyFinalOverriders; if (!FinalOverriders) { getFinalOverriders(MyFinalOverriders); FinalOverriders = &MyFinalOverriders; } bool Done = false; for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(), MEnd = FinalOverriders->end(); M != MEnd && !Done; ++M) { for (OverridingMethods::iterator SO = M->second.begin(), SOEnd = M->second.end(); SO != SOEnd && !Done; ++SO) { assert(SO->second.size() > 0 && "All virtual functions have overridding virtual functions"); // C++ [class.abstract]p4: // A class is abstract if it contains or inherits at least one // pure virtual function for which the final overrider is pure // virtual. if (SO->second.front().Method->isPure()) { data().Abstract = true; Done = true; break; } } } } // Set access bits correctly on the directly-declared conversions. for (conversion_iterator I = conversion_begin(), E = conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); } bool CXXRecordDecl::mayBeAbstract() const { if (data().Abstract || isInvalidDecl() || !data().Polymorphic || isDependentContext()) return false; for (const auto &B : bases()) { CXXRecordDecl *BaseDecl = cast(B.getType()->getAs()->getDecl()); if (BaseDecl->isAbstract()) return true; } return false; } void CXXMethodDecl::anchor() { } bool CXXMethodDecl::isStatic() const { const CXXMethodDecl *MD = getCanonicalDecl(); if (MD->getStorageClass() == SC_Static) return true; OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator(); return isStaticOverloadedOperator(OOK); } static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(), E = DerivedMD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *MD = *I; if (MD->getCanonicalDecl() == BaseMD->getCanonicalDecl()) return true; if (recursivelyOverrides(MD, BaseMD)) return true; } return false; } CXXMethodDecl * CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, bool MayBeBase) { if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl()) return this; // Lookup doesn't work for destructors, so handle them separately. if (isa(this)) { CXXMethodDecl *MD = RD->getDestructor(); if (MD) { if (recursivelyOverrides(MD, this)) return MD; if (MayBeBase && recursivelyOverrides(this, MD)) return MD; } return nullptr; } lookup_const_result Candidates = RD->lookup(getDeclName()); for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) { CXXMethodDecl *MD = dyn_cast(*I); if (!MD) continue; if (recursivelyOverrides(MD, this)) return MD; if (MayBeBase && recursivelyOverrides(this, MD)) return MD; } for (const auto &I : RD->bases()) { const RecordType *RT = I.getType()->getAs(); if (!RT) continue; const CXXRecordDecl *Base = cast(RT->getDecl()); CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base); if (T) return T; } return nullptr; } CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool isInline, bool isConstexpr, SourceLocation EndLocation) { return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, isInline, isConstexpr, EndLocation); } CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, SC_None, false, false, SourceLocation()); } bool CXXMethodDecl::isUsualDeallocationFunction() const { if (getOverloadedOperator() != OO_Delete && getOverloadedOperator() != OO_Array_Delete) return false; // C++ [basic.stc.dynamic.deallocation]p2: // A template instance is never a usual deallocation function, // regardless of its signature. if (getPrimaryTemplate()) return false; // C++ [basic.stc.dynamic.deallocation]p2: // If a class T has a member deallocation function named operator delete // with exactly one parameter, then that function is a usual (non-placement) // deallocation function. [...] if (getNumParams() == 1) return true; // C++ [basic.stc.dynamic.deallocation]p2: // [...] If class T does not declare such an operator delete but does // declare a member deallocation function named operator delete with // exactly two parameters, the second of which has type std::size_t (18.1), // then this function is a usual deallocation function. ASTContext &Context = getASTContext(); if (getNumParams() != 2 || !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(), Context.getSizeType())) return false; // This function is a usual deallocation function if there are no // single-parameter deallocation functions of the same kind. DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (const FunctionDecl *FD = dyn_cast(*I)) if (FD->getNumParams() == 1) return false; } return true; } bool CXXMethodDecl::isCopyAssignmentOperator() const { // C++0x [class.copy]p17: // A user-declared copy assignment operator X::operator= is a non-static // non-template member function of class X with exactly one parameter of // type X, X&, const X&, volatile X& or const volatile X&. if (/*operator=*/getOverloadedOperator() != OO_Equal || /*non-static*/ isStatic() || /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); if (const LValueReferenceType *Ref = ParamType->getAs()) ParamType = Ref->getPointeeType(); ASTContext &Context = getASTContext(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(getParent())); return Context.hasSameUnqualifiedType(ClassType, ParamType); } bool CXXMethodDecl::isMoveAssignmentOperator() const { // C++0x [class.copy]p19: // A user-declared move assignment operator X::operator= is a non-static // non-template member function of class X with exactly one parameter of type // X&&, const X&&, volatile X&&, or const volatile X&&. if (getOverloadedOperator() != OO_Equal || isStatic() || getPrimaryTemplate() || getDescribedFunctionTemplate() || getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); if (!isa(ParamType)) return false; ParamType = ParamType->getPointeeType(); ASTContext &Context = getASTContext(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(getParent())); return Context.hasSameUnqualifiedType(ClassType, ParamType); } void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && "Can't add an overridden method to a class template!"); assert(MD->isVirtual() && "Method is not virtual!"); getASTContext().addOverriddenMethod(this, MD); } CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { if (isa(this)) return nullptr; return getASTContext().overridden_methods_begin(this); } CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { if (isa(this)) return nullptr; return getASTContext().overridden_methods_end(this); } unsigned CXXMethodDecl::size_overridden_methods() const { if (isa(this)) return 0; return getASTContext().overridden_methods_size(this); } QualType CXXMethodDecl::getThisType(ASTContext &C) const { // C++ 9.3.2p1: The type of this in a member function of a class X is X*. // If the member function is declared const, the type of this is const X*, // if the member function is declared volatile, the type of this is // volatile X*, and if the member function is declared const volatile, // the type of this is const volatile X*. assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTypeDeclType(getParent()); ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); } bool CXXMethodDecl::hasInlineBody() const { // If this function is a template instantiation, look at the template from // which it was instantiated. const FunctionDecl *CheckFn = getTemplateInstantiationPattern(); if (!CheckFn) CheckFn = this; const FunctionDecl *fn; return CheckFn->hasBody(fn) && !fn->isOutOfLine(); } bool CXXMethodDecl::isLambdaStaticInvoker() const { const CXXRecordDecl *P = getParent(); if (P->isLambda()) { if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) { if (StaticInvoker == this) return true; if (P->isGenericLambda() && this->isFunctionTemplateSpecialization()) return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl(); } } return false; } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R, SourceLocation EllipsisLoc) : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(IsVirtual), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R) : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R) : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, SourceLocation L, Expr *Init, SourceLocation R) : Initializee(TInfo), MemberOrEllipsisLocation(), Init(Init), LParenLoc(L), RParenLoc(R), IsDelegating(true), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R, VarDecl **Indices, unsigned NumIndices) : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), LParenLoc(L), RParenLoc(R), IsDelegating(false), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices) { VarDecl **MyIndices = reinterpret_cast (this + 1); memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *)); } CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, SourceLocation R, VarDecl **Indices, unsigned NumIndices) { void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) + sizeof(VarDecl *) * NumIndices, llvm::alignOf()); return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R, Indices, NumIndices); } TypeLoc CXXCtorInitializer::getBaseClassLoc() const { if (isBaseInitializer()) return Initializee.get()->getTypeLoc(); else return TypeLoc(); } const Type *CXXCtorInitializer::getBaseClass() const { if (isBaseInitializer()) return Initializee.get()->getType().getTypePtr(); else return nullptr; } SourceLocation CXXCtorInitializer::getSourceLocation() const { - if (isAnyMemberInitializer()) - return getMemberLocation(); - if (isInClassMemberInitializer()) return getAnyMember()->getLocation(); + if (isAnyMemberInitializer()) + return getMemberLocation(); + if (TypeSourceInfo *TSInfo = Initializee.get()) return TSInfo->getTypeLoc().getLocalSourceRange().getBegin(); return SourceLocation(); } SourceRange CXXCtorInitializer::getSourceRange() const { if (isInClassMemberInitializer()) { FieldDecl *D = getAnyMember(); if (Expr *I = D->getInClassInitializer()) return I->getSourceRange(); return SourceRange(); } return SourceRange(getSourceLocation(), getRParenLoc()); } void CXXConstructorDecl::anchor() { } CXXConstructorDecl * CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, false, false, false, false); } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared, bool isConstexpr) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); return new (C, RD) CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, isImplicitlyDeclared, isConstexpr); } CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const { assert(isDelegatingConstructor() && "Not a delegating constructor!"); Expr *E = (*init_begin())->getInit()->IgnoreImplicit(); if (CXXConstructExpr *Construct = dyn_cast(E)) return Construct->getConstructor(); return nullptr; } bool CXXConstructorDecl::isDefaultConstructor() const { // C++ [class.ctor]p5: // A default constructor for a class X is a constructor of class // X that can be called without an argument. return (getNumParams() == 0) || (getNumParams() > 0 && getParamDecl(0)->hasDefaultArg()); } bool CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const { return isCopyOrMoveConstructor(TypeQuals) && getParamDecl(0)->getType()->isLValueReferenceType(); } bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const { return isCopyOrMoveConstructor(TypeQuals) && getParamDecl(0)->getType()->isRValueReferenceType(); } /// \brief Determine whether this is a copy or move constructor. bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor // if its first parameter is of type X&, const X&, volatile X& or // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). // C++0x [class.copy]p3: // A non-template constructor for class X is a move constructor if its // first parameter is of type X&&, const X&&, volatile X&&, or // const volatile X&&, and either there are no other parameters or else // all other parameters have default arguments. if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getPrimaryTemplate() != nullptr) || (getDescribedFunctionTemplate() != nullptr)) return false; const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? const ReferenceType *ParamRefType = Param->getType()->getAs(); if (!ParamRefType) return false; // Is it a reference to our class type? ASTContext &Context = getASTContext(); CanQualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); CanQualType ClassTy = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; // FIXME: other qualifiers? // We have a copy or move constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; } bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { // C++ [class.conv.ctor]p1: // A constructor declared without the function-specifier explicit // that can be called with a single parameter specifies a // conversion from the type of its first parameter to the type of // its class. Such a constructor is called a converting // constructor. if (isExplicit() && !AllowExplicit) return false; return (getNumParams() == 0 && getType()->getAs()->isVariadic()) || (getNumParams() == 1) || (getNumParams() > 1 && (getParamDecl(1)->hasDefaultArg() || getParamDecl(1)->isParameterPack())); } bool CXXConstructorDecl::isSpecializationCopyingObject() const { if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getDescribedFunctionTemplate() != nullptr)) return false; const ParmVarDecl *Param = getParamDecl(0); ASTContext &Context = getASTContext(); CanQualType ParamType = Context.getCanonicalType(Param->getType()); // Is it the same as our our class type? CanQualType ClassTy = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (ParamType.getUnqualifiedType() != ClassTy) return false; return true; } const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const { // Hack: we store the inherited constructor in the overridden method table method_iterator It = getASTContext().overridden_methods_begin(this); if (It == getASTContext().overridden_methods_end(this)) return nullptr; return cast(*It); } void CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ // Hack: we store the inherited constructor in the overridden method table assert(getASTContext().overridden_methods_size(this) == 0 && "Base ctor already set."); getASTContext().addOverriddenMethod(this, BaseCtor); } void CXXDestructorDecl::anchor() { } CXXDestructorDecl * CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, false, false); } CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isImplicitlyDeclared) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, isImplicitlyDeclared); } void CXXConversionDecl::anchor() { } CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, false, false, false, SourceLocation()); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit, bool isConstexpr, SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, isExplicit, isConstexpr, EndLocation); } bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { return isImplicit() && getParent()->isLambda() && getConversionType()->isBlockPointerType(); } void LinkageSpecDecl::anchor() { } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs Lang, bool HasBraces) { return new (C, DC) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces); } LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) LinkageSpecDecl(nullptr, SourceLocation(), SourceLocation(), lang_c, false); } void UsingDirectiveDecl::anchor() { } UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, SourceLocation NamespaceLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, NamedDecl *Used, DeclContext *CommonAncestor) { if (NamespaceDecl *NS = dyn_cast_or_null(Used)) Used = NS->getOriginalNamespace(); return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc, IdentLoc, Used, CommonAncestor); } UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UsingDirectiveDecl(nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), nullptr, nullptr); } NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { if (NamespaceAliasDecl *NA = dyn_cast_or_null(NominatedNamespace)) return NA->getNamespace(); return cast_or_null(NominatedNamespace); } NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl) : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), redeclarable_base(C), LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(nullptr, Inline) { setPreviousDecl(PrevDecl); if (PrevDecl) AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace()); } NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl) { return new (C, DC) NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl); } NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(), SourceLocation(), nullptr, nullptr); } NamespaceDecl *NamespaceDecl::getNextRedeclarationImpl() { return getNextRedeclaration(); } NamespaceDecl *NamespaceDecl::getPreviousDeclImpl() { return getPreviousDecl(); } NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() { return getMostRecentDecl(); } void NamespaceAliasDecl::anchor() { } NamespaceAliasDecl *NamespaceAliasDecl::getNextRedeclarationImpl() { return getNextRedeclaration(); } NamespaceAliasDecl *NamespaceAliasDecl::getPreviousDeclImpl() { return getPreviousDecl(); } NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() { return getMostRecentDecl(); } NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, NamedDecl *Namespace) { // FIXME: Preserve the aliased namespace as written. if (NamespaceDecl *NS = dyn_cast_or_null(Namespace)) Namespace = NS->getOriginalNamespace(); return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias, QualifierLoc, IdentLoc, Namespace); } NamespaceAliasDecl * NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) NamespaceAliasDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, NestedNameSpecifierLoc(), SourceLocation(), nullptr); } void UsingShadowDecl::anchor() { } UsingShadowDecl * UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UsingShadowDecl(C, nullptr, SourceLocation(), nullptr, nullptr); } UsingDecl *UsingShadowDecl::getUsingDecl() const { const UsingShadowDecl *Shadow = this; while (const UsingShadowDecl *NextShadow = dyn_cast(Shadow->UsingOrNextShadow)) Shadow = NextShadow; return cast(Shadow->UsingOrNextShadow); } void UsingDecl::anchor() { } void UsingDecl::addShadowDecl(UsingShadowDecl *S) { assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && "declaration already in set"); assert(S->getUsingDecl() == this); if (FirstUsingShadow.getPointer()) S->UsingOrNextShadow = FirstUsingShadow.getPointer(); FirstUsingShadow.setPointer(S); } void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() && "declaration not in set"); assert(S->getUsingDecl() == this); // Remove S from the shadow decl chain. This is O(n) but hopefully rare. if (FirstUsingShadow.getPointer() == S) { FirstUsingShadow.setPointer( dyn_cast(S->UsingOrNextShadow)); S->UsingOrNextShadow = this; return; } UsingShadowDecl *Prev = FirstUsingShadow.getPointer(); while (Prev->UsingOrNextShadow != S) Prev = cast(Prev->UsingOrNextShadow); Prev->UsingOrNextShadow = S->UsingOrNextShadow; S->UsingOrNextShadow = this; } UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, bool HasTypename) { return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); } UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UsingDecl(nullptr, SourceLocation(), NestedNameSpecifierLoc(), DeclarationNameInfo(), false); } SourceRange UsingDecl::getSourceRange() const { SourceLocation Begin = isAccessDeclaration() ? getQualifierLoc().getBeginLoc() : UsingLocation; return SourceRange(Begin, getNameInfo().getEndLoc()); } void UnresolvedUsingValueDecl::anchor() { } UnresolvedUsingValueDecl * UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) { return new (C, DC) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, QualifierLoc, NameInfo); } UnresolvedUsingValueDecl * UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UnresolvedUsingValueDecl(nullptr, QualType(), SourceLocation(), NestedNameSpecifierLoc(), DeclarationNameInfo()); } SourceRange UnresolvedUsingValueDecl::getSourceRange() const { SourceLocation Begin = isAccessDeclaration() ? getQualifierLoc().getBeginLoc() : UsingLocation; return SourceRange(Begin, getNameInfo().getEndLoc()); } void UnresolvedUsingTypenameDecl::anchor() { } UnresolvedUsingTypenameDecl * UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TargetNameLoc, DeclarationName TargetName) { return new (C, DC) UnresolvedUsingTypenameDecl( DC, UsingLoc, TypenameLoc, QualifierLoc, TargetNameLoc, TargetName.getAsIdentifierInfo()); } UnresolvedUsingTypenameDecl * UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) UnresolvedUsingTypenameDecl( nullptr, SourceLocation(), SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), nullptr); } void StaticAssertDecl::anchor() { } StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *Message, SourceLocation RParenLoc, bool Failed) { return new (C, DC) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message, RParenLoc, Failed); } StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) StaticAssertDecl(nullptr, SourceLocation(), nullptr, nullptr, SourceLocation(), false); } MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, SourceLocation StartL, IdentifierInfo *Getter, IdentifierInfo *Setter) { return new (C, DC) MSPropertyDecl(DC, L, N, T, TInfo, StartL, Getter, Setter); } MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) MSPropertyDecl(nullptr, SourceLocation(), DeclarationName(), QualType(), nullptr, SourceLocation(), nullptr, nullptr); } static const char *getAccessName(AccessSpecifier AS) { switch (AS) { case AS_none: llvm_unreachable("Invalid access specifier!"); case AS_public: return "public"; case AS_private: return "private"; case AS_protected: return "protected"; } llvm_unreachable("Invalid access specifier!"); } const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, AccessSpecifier AS) { return DB << getAccessName(AS); } const PartialDiagnostic &clang::operator<<(const PartialDiagnostic &DB, AccessSpecifier AS) { return DB << getAccessName(AS); } Index: vendor/clang/dist/lib/CodeGen/CGClass.cpp =================================================================== --- vendor/clang/dist/lib/CodeGen/CGClass.cpp (revision 278753) +++ vendor/clang/dist/lib/CodeGen/CGClass.cpp (revision 278754) @@ -1,2277 +1,2276 @@ //===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code dealing with C++ code generation of classes // //===----------------------------------------------------------------------===// #include "CGBlocks.h" #include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" using namespace clang; using namespace CodeGen; static CharUnits ComputeNonVirtualBaseClassOffset(ASTContext &Context, const CXXRecordDecl *DerivedClass, CastExpr::path_const_iterator Start, CastExpr::path_const_iterator End) { CharUnits Offset = CharUnits::Zero(); const CXXRecordDecl *RD = DerivedClass; for (CastExpr::path_const_iterator I = Start; I != End; ++I) { const CXXBaseSpecifier *Base = *I; assert(!Base->isVirtual() && "Should not see virtual bases here!"); // Get the layout. const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); const CXXRecordDecl *BaseDecl = cast(Base->getType()->getAs()->getDecl()); // Add the offset. Offset += Layout.getBaseClassOffset(BaseDecl); RD = BaseDecl; } return Offset; } llvm::Constant * CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd) { assert(PathBegin != PathEnd && "Base path should not be empty!"); CharUnits Offset = ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, PathBegin, PathEnd); if (Offset.isZero()) return nullptr; llvm::Type *PtrDiffTy = Types.ConvertType(getContext().getPointerDiffType()); return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity()); } /// Gets the address of a direct base class within a complete object. /// This should only be used for (1) non-virtual bases or (2) virtual bases /// when the type is known to be complete (e.g. in complete destructors). /// /// The object pointed to by 'This' is assumed to be non-null. llvm::Value * CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, const CXXRecordDecl *Derived, const CXXRecordDecl *Base, bool BaseIsVirtual) { // 'this' must be a pointer (in some address space) to Derived. assert(This->getType()->isPointerTy() && cast(This->getType())->getElementType() == ConvertType(Derived)); // Compute the offset of the virtual base. CharUnits Offset; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); if (BaseIsVirtual) Offset = Layout.getVBaseClassOffset(Base); else Offset = Layout.getBaseClassOffset(Base); // Shift and cast down to the base type. // TODO: for complete types, this should be possible with a GEP. llvm::Value *V = This; if (Offset.isPositive()) { V = Builder.CreateBitCast(V, Int8PtrTy); V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity()); } V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo()); return V; } static llvm::Value * ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ptr, CharUnits nonVirtualOffset, llvm::Value *virtualOffset) { // Assert that we have something to do. assert(!nonVirtualOffset.isZero() || virtualOffset != nullptr); // Compute the offset from the static and dynamic components. llvm::Value *baseOffset; if (!nonVirtualOffset.isZero()) { baseOffset = llvm::ConstantInt::get(CGF.PtrDiffTy, nonVirtualOffset.getQuantity()); if (virtualOffset) { baseOffset = CGF.Builder.CreateAdd(virtualOffset, baseOffset); } } else { baseOffset = virtualOffset; } // Apply the base offset. ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy); ptr = CGF.Builder.CreateInBoundsGEP(ptr, baseOffset, "add.ptr"); return ptr; } llvm::Value *CodeGenFunction::GetAddressOfBaseClass( llvm::Value *Value, const CXXRecordDecl *Derived, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd, bool NullCheckValue, SourceLocation Loc) { assert(PathBegin != PathEnd && "Base path should not be empty!"); CastExpr::path_const_iterator Start = PathBegin; const CXXRecordDecl *VBase = nullptr; // Sema has done some convenient canonicalization here: if the // access path involved any virtual steps, the conversion path will // *start* with a step down to the correct virtual base subobject, // and hence will not require any further steps. if ((*Start)->isVirtual()) { VBase = cast((*Start)->getType()->getAs()->getDecl()); ++Start; } // Compute the static offset of the ultimate destination within its // allocating subobject (the virtual base, if there is one, or else // the "complete" object that we see). CharUnits NonVirtualOffset = ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, Start, PathEnd); // If there's a virtual step, we can sometimes "devirtualize" it. // For now, that's limited to when the derived type is final. // TODO: "devirtualize" this for accesses to known-complete objects. if (VBase && Derived->hasAttr()) { const ASTRecordLayout &layout = getContext().getASTRecordLayout(Derived); CharUnits vBaseOffset = layout.getVBaseClassOffset(VBase); NonVirtualOffset += vBaseOffset; VBase = nullptr; // we no longer have a virtual step } // Get the base pointer type. llvm::Type *BasePtrTy = ConvertType((PathEnd[-1])->getType())->getPointerTo(); QualType DerivedTy = getContext().getRecordType(Derived); CharUnits DerivedAlign = getContext().getTypeAlignInChars(DerivedTy); // If the static offset is zero and we don't have a virtual step, // just do a bitcast; null checks are unnecessary. if (NonVirtualOffset.isZero() && !VBase) { if (sanitizePerformTypeCheck()) { EmitTypeCheck(TCK_Upcast, Loc, Value, DerivedTy, DerivedAlign, !NullCheckValue); } return Builder.CreateBitCast(Value, BasePtrTy); } llvm::BasicBlock *origBB = nullptr; llvm::BasicBlock *endBB = nullptr; // Skip over the offset (and the vtable load) if we're supposed to // null-check the pointer. if (NullCheckValue) { origBB = Builder.GetInsertBlock(); llvm::BasicBlock *notNullBB = createBasicBlock("cast.notnull"); endBB = createBasicBlock("cast.end"); llvm::Value *isNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(isNull, endBB, notNullBB); EmitBlock(notNullBB); } if (sanitizePerformTypeCheck()) { EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc, Value, DerivedTy, DerivedAlign, true); } // Compute the virtual offset. llvm::Value *VirtualOffset = nullptr; if (VBase) { VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase); } // Apply both offsets. Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, VirtualOffset); // Cast to the destination type. Value = Builder.CreateBitCast(Value, BasePtrTy); // Build a phi if we needed a null check. if (NullCheckValue) { llvm::BasicBlock *notNullBB = Builder.GetInsertBlock(); Builder.CreateBr(endBB); EmitBlock(endBB); llvm::PHINode *PHI = Builder.CreatePHI(BasePtrTy, 2, "cast.result"); PHI->addIncoming(Value, notNullBB); PHI->addIncoming(llvm::Constant::getNullValue(BasePtrTy), origBB); Value = PHI; } return Value; } llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, const CXXRecordDecl *Derived, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd, bool NullCheckValue) { assert(PathBegin != PathEnd && "Base path should not be empty!"); QualType DerivedTy = getContext().getCanonicalType(getContext().getTagDeclType(Derived)); llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); llvm::Value *NonVirtualOffset = CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd); if (!NonVirtualOffset) { // No offset, we can just cast back. return Builder.CreateBitCast(Value, DerivedPtrTy); } llvm::BasicBlock *CastNull = nullptr; llvm::BasicBlock *CastNotNull = nullptr; llvm::BasicBlock *CastEnd = nullptr; if (NullCheckValue) { CastNull = createBasicBlock("cast.null"); CastNotNull = createBasicBlock("cast.notnull"); CastEnd = createBasicBlock("cast.end"); llvm::Value *IsNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } // Apply the offset. Value = Builder.CreateBitCast(Value, Int8PtrTy); Value = Builder.CreateGEP(Value, Builder.CreateNeg(NonVirtualOffset), "sub.ptr"); // Just cast. Value = Builder.CreateBitCast(Value, DerivedPtrTy); if (NullCheckValue) { Builder.CreateBr(CastEnd); EmitBlock(CastNull); Builder.CreateBr(CastEnd); EmitBlock(CastEnd); llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); Value = PHI; } return Value; } llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, bool ForVirtualBase, bool Delegating) { if (!CGM.getCXXABI().NeedsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return nullptr; } const CXXRecordDecl *RD = cast(CurCodeDecl)->getParent(); const CXXRecordDecl *Base = cast(GD.getDecl())->getParent(); llvm::Value *VTT; uint64_t SubVTTIndex; if (Delegating) { // If this is a delegating constructor call, just load the VTT. return LoadCXXVTT(); } else if (RD == Base) { // If the record matches the base, this is the complete ctor/dtor // variant calling the base variant in a class with virtual bases. assert(!CGM.getCXXABI().NeedsVTTParameter(CurGD) && "doing no-op VTT offset in base dtor/ctor?"); assert(!ForVirtualBase && "Can't have same class as virtual base!"); SubVTTIndex = 0; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); CharUnits BaseOffset = ForVirtualBase ? Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base); SubVTTIndex = CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) { // A VTT parameter was passed to the constructor, use it. VTT = LoadCXXVTT(); VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); } else { // We're the complete constructor, so get the VTT by name. VTT = CGM.getVTables().GetAddrOfVTT(RD); VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); } return VTT; } namespace { /// Call the destructor for a direct base class. struct CallBaseDtor : EHScopeStack::Cleanup { const CXXRecordDecl *BaseClass; bool BaseIsVirtual; CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual) : BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {} void Emit(CodeGenFunction &CGF, Flags flags) override { const CXXRecordDecl *DerivedClass = cast(CGF.CurCodeDecl)->getParent(); const CXXDestructorDecl *D = BaseClass->getDestructor(); llvm::Value *Addr = CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(), DerivedClass, BaseClass, BaseIsVirtual); CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual, /*Delegating=*/false, Addr); } }; /// A visitor which checks whether an initializer uses 'this' in a /// way which requires the vtable to be properly set. struct DynamicThisUseChecker : EvaluatedExprVisitor { typedef EvaluatedExprVisitor super; bool UsesThis; DynamicThisUseChecker(ASTContext &C) : super(C), UsesThis(false) {} // Black-list all explicit and implicit references to 'this'. // // Do we need to worry about external references to 'this' derived // from arbitrary code? If so, then anything which runs arbitrary // external code might potentially access the vtable. void VisitCXXThisExpr(CXXThisExpr *E) { UsesThis = true; } }; } static bool BaseInitializerUsesThis(ASTContext &C, const Expr *Init) { DynamicThisUseChecker Checker(C); Checker.Visit(const_cast(Init)); return Checker.UsesThis; } static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXCtorInitializer *BaseInit, CXXCtorType CtorType) { assert(BaseInit->isBaseInitializer() && "Must have base initializer!"); llvm::Value *ThisPtr = CGF.LoadCXXThis(); const Type *BaseType = BaseInit->getBaseClass(); CXXRecordDecl *BaseClassDecl = cast(BaseType->getAs()->getDecl()); bool isBaseVirtual = BaseInit->isBaseVirtual(); // The base constructor doesn't construct virtual bases. if (CtorType == Ctor_Base && isBaseVirtual) return; // If the initializer for the base (other than the constructor // itself) accesses 'this' in any way, we need to initialize the // vtables. if (BaseInitializerUsesThis(CGF.getContext(), BaseInit->getInit())) CGF.InitializeVTablePointers(ClassDecl); // We can pretend to be a complete class because it only matters for // virtual bases, and we only do virtual bases for complete ctors. llvm::Value *V = CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl, BaseClassDecl, isBaseVirtual); CharUnits Alignment = CGF.getContext().getTypeAlignInChars(BaseType); AggValueSlot AggSlot = AggValueSlot::forAddr(V, Alignment, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); CGF.EmitAggExpr(BaseInit->getInit(), AggSlot); if (CGF.CGM.getLangOpts().Exceptions && !BaseClassDecl->hasTrivialDestructor()) CGF.EHStack.pushCleanup(EHCleanup, BaseClassDecl, isBaseVirtual); } static void EmitAggMemberInitializer(CodeGenFunction &CGF, LValue LHS, Expr *Init, llvm::Value *ArrayIndexVar, QualType T, ArrayRef ArrayIndexes, unsigned Index) { if (Index == ArrayIndexes.size()) { LValue LV = LHS; if (ArrayIndexVar) { // If we have an array index variable, load it and use it as an offset. // Then, increment the value. llvm::Value *Dest = LHS.getAddress(); llvm::Value *ArrayIndex = CGF.Builder.CreateLoad(ArrayIndexVar); Dest = CGF.Builder.CreateInBoundsGEP(Dest, ArrayIndex, "destaddress"); llvm::Value *Next = llvm::ConstantInt::get(ArrayIndex->getType(), 1); Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc"); CGF.Builder.CreateStore(Next, ArrayIndexVar); // Update the LValue. LV.setAddress(Dest); CharUnits Align = CGF.getContext().getTypeAlignInChars(T); LV.setAlignment(std::min(Align, LV.getAlignment())); } switch (CGF.getEvaluationKind(T)) { case TEK_Scalar: CGF.EmitScalarInit(Init, /*decl*/ nullptr, LV, false); break; case TEK_Complex: CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true); break; case TEK_Aggregate: { AggValueSlot Slot = AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); CGF.EmitAggExpr(Init, Slot); break; } } return; } const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(T); assert(Array && "Array initialization without the array type?"); llvm::Value *IndexVar = CGF.GetAddrOfLocalVar(ArrayIndexes[Index]); assert(IndexVar && "Array index variable not loaded"); // Initialize this index variable to zero. llvm::Value* Zero = llvm::Constant::getNullValue( CGF.ConvertType(CGF.getContext().getSizeType())); CGF.Builder.CreateStore(Zero, IndexVar); // Start the loop with a block that tests the condition. llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond"); llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end"); CGF.EmitBlock(CondBlock); llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body"); // Generate: if (loop-index < number-of-elements) fall to the loop body, // otherwise, go to the block after the for-loop. uint64_t NumElements = Array->getSize().getZExtValue(); llvm::Value *Counter = CGF.Builder.CreateLoad(IndexVar); llvm::Value *NumElementsPtr = llvm::ConstantInt::get(Counter->getType(), NumElements); llvm::Value *IsLess = CGF.Builder.CreateICmpULT(Counter, NumElementsPtr, "isless"); // If the condition is true, execute the body. CGF.Builder.CreateCondBr(IsLess, ForBody, AfterFor); CGF.EmitBlock(ForBody); llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc"); // Inside the loop body recurse to emit the inner loop or, eventually, the // constructor call. EmitAggMemberInitializer(CGF, LHS, Init, ArrayIndexVar, Array->getElementType(), ArrayIndexes, Index + 1); CGF.EmitBlock(ContinueBlock); // Emit the increment of the loop counter. llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); Counter = CGF.Builder.CreateLoad(IndexVar); NextVal = CGF.Builder.CreateAdd(Counter, NextVal, "inc"); CGF.Builder.CreateStore(NextVal, IndexVar); // Finally, branch back up to the condition for the next iteration. CGF.EmitBranch(CondBlock); // Emit the fall-through block. CGF.EmitBlock(AfterFor, true); } static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXCtorInitializer *MemberInit, const CXXConstructorDecl *Constructor, FunctionArgList &Args) { - ApplyDebugLocation Loc(CGF, MemberInit->getMemberLocation()); + ApplyDebugLocation Loc(CGF, MemberInit->getSourceLocation()); assert(MemberInit->isAnyMemberInitializer() && "Must have member initializer!"); assert(MemberInit->getInit() && "Must have initializer!"); // non-static data member initializers. FieldDecl *Field = MemberInit->getAnyMember(); QualType FieldType = Field->getType(); llvm::Value *ThisPtr = CGF.LoadCXXThis(); QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); if (MemberInit->isIndirectMemberInitializer()) { // If we are initializing an anonymous union field, drill down to // the field. IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember(); for (const auto *I : IndirectField->chain()) LHS = CGF.EmitLValueForFieldInitialization(LHS, cast(I)); FieldType = MemberInit->getIndirectMember()->getAnonField()->getType(); } else { LHS = CGF.EmitLValueForFieldInitialization(LHS, Field); } // Special case: if we are in a copy or move constructor, and we are copying // an array of PODs or classes with trivial copy constructors, ignore the // AST and perform the copy we know is equivalent. // FIXME: This is hacky at best... if we had a bit more explicit information // in the AST, we could generalize it more easily. const ConstantArrayType *Array = CGF.getContext().getAsConstantArrayType(FieldType); if (Array && Constructor->isDefaulted() && Constructor->isCopyOrMoveConstructor()) { QualType BaseElementTy = CGF.getContext().getBaseElementType(Array); CXXConstructExpr *CE = dyn_cast(MemberInit->getInit()); if (BaseElementTy.isPODType(CGF.getContext()) || (CE && CE->getConstructor()->isTrivial())) { unsigned SrcArgIndex = CGF.CGM.getCXXABI().getSrcArgforCopyCtor(Constructor, Args); llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex])); LValue ThisRHSLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); LValue Src = CGF.EmitLValueForFieldInitialization(ThisRHSLV, Field); // Copy the aggregate. CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType, LHS.isVolatileQualified()); return; } } ArrayRef ArrayIndexes; if (MemberInit->getNumArrayIndices()) ArrayIndexes = MemberInit->getArrayIndexes(); - ApplyDebugLocation DL(CGF, MemberInit->getMemberLocation()); CGF.EmitInitializerForField(Field, LHS, MemberInit->getInit(), ArrayIndexes); } void CodeGenFunction::EmitInitializerForField( FieldDecl *Field, LValue LHS, Expr *Init, ArrayRef ArrayIndexes) { QualType FieldType = Field->getType(); switch (getEvaluationKind(FieldType)) { case TEK_Scalar: if (LHS.isSimple()) { EmitExprAsInit(Init, Field, LHS, false); } else { RValue RHS = RValue::get(EmitScalarExpr(Init)); EmitStoreThroughLValue(RHS, LHS); } break; case TEK_Complex: EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true); break; case TEK_Aggregate: { llvm::Value *ArrayIndexVar = nullptr; if (ArrayIndexes.size()) { llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); // The LHS is a pointer to the first object we'll be constructing, as // a flat array. QualType BaseElementTy = getContext().getBaseElementType(FieldType); llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr); LHS = MakeAddrLValue(BaseAddrPtr, BaseElementTy); // Create an array index that will be used to walk over all of the // objects we're constructing. ArrayIndexVar = CreateTempAlloca(SizeTy, "object.index"); llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); Builder.CreateStore(Zero, ArrayIndexVar); // Emit the block variables for the array indices, if any. for (unsigned I = 0, N = ArrayIndexes.size(); I != N; ++I) EmitAutoVarDecl(*ArrayIndexes[I]); } EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType, ArrayIndexes, 0); } } // Ensure that we destroy this object if an exception is thrown // later in the constructor. QualType::DestructionKind dtorKind = FieldType.isDestructedType(); if (needsEHCleanup(dtorKind)) pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); } /// Checks whether the given constructor is a valid subject for the /// complete-to-base constructor delegation optimization, i.e. /// emitting the complete constructor as a simple call to the base /// constructor. static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) { // Currently we disable the optimization for classes with virtual // bases because (1) the addresses of parameter variables need to be // consistent across all initializers but (2) the delegate function // call necessarily creates a second copy of the parameter variable. // // The limiting example (purely theoretical AFAIK): // struct A { A(int &c) { c++; } }; // struct B : virtual A { // B(int count) : A(count) { printf("%d\n", count); } // }; // ...although even this example could in principle be emitted as a // delegation since the address of the parameter doesn't escape. if (Ctor->getParent()->getNumVBases()) { // TODO: white-list trivial vbase initializers. This case wouldn't // be subject to the restrictions below. // TODO: white-list cases where: // - there are no non-reference parameters to the constructor // - the initializers don't access any non-reference parameters // - the initializers don't take the address of non-reference // parameters // - etc. // If we ever add any of the above cases, remember that: // - function-try-blocks will always blacklist this optimization // - we need to perform the constructor prologue and cleanup in // EmitConstructorBody. return false; } // We also disable the optimization for variadic functions because // it's impossible to "re-pass" varargs. if (Ctor->getType()->getAs()->isVariadic()) return false; // FIXME: Decide if we can do a delegation of a delegating constructor. if (Ctor->isDelegatingConstructor()) return false; return true; } // Emit code in ctor (Prologue==true) or dtor (Prologue==false) // to poison the extra field paddings inserted under // -fsanitize-address-field-padding=1|2. void CodeGenFunction::EmitAsanPrologueOrEpilogue(bool Prologue) { ASTContext &Context = getContext(); const CXXRecordDecl *ClassDecl = Prologue ? cast(CurGD.getDecl())->getParent() : cast(CurGD.getDecl())->getParent(); if (!ClassDecl->mayInsertExtraPadding()) return; struct SizeAndOffset { uint64_t Size; uint64_t Offset; }; unsigned PtrSize = CGM.getDataLayout().getPointerSizeInBits(); const ASTRecordLayout &Info = Context.getASTRecordLayout(ClassDecl); // Populate sizes and offsets of fields. SmallVector SSV(Info.getFieldCount()); for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) SSV[i].Offset = Context.toCharUnitsFromBits(Info.getFieldOffset(i)).getQuantity(); size_t NumFields = 0; for (const auto *Field : ClassDecl->fields()) { const FieldDecl *D = Field; std::pair FieldInfo = Context.getTypeInfoInChars(D->getType()); CharUnits FieldSize = FieldInfo.first; assert(NumFields < SSV.size()); SSV[NumFields].Size = D->isBitField() ? 0 : FieldSize.getQuantity(); NumFields++; } assert(NumFields == SSV.size()); if (SSV.size() <= 1) return; // We will insert calls to __asan_* run-time functions. // LLVM AddressSanitizer pass may decide to inline them later. llvm::Type *Args[2] = {IntPtrTy, IntPtrTy}; llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, Args, false); llvm::Constant *F = CGM.CreateRuntimeFunction( FTy, Prologue ? "__asan_poison_intra_object_redzone" : "__asan_unpoison_intra_object_redzone"); llvm::Value *ThisPtr = LoadCXXThis(); ThisPtr = Builder.CreatePtrToInt(ThisPtr, IntPtrTy); uint64_t TypeSize = Info.getNonVirtualSize().getQuantity(); // For each field check if it has sufficient padding, // if so (un)poison it with a call. for (size_t i = 0; i < SSV.size(); i++) { uint64_t AsanAlignment = 8; uint64_t NextField = i == SSV.size() - 1 ? TypeSize : SSV[i + 1].Offset; uint64_t PoisonSize = NextField - SSV[i].Offset - SSV[i].Size; uint64_t EndOffset = SSV[i].Offset + SSV[i].Size; if (PoisonSize < AsanAlignment || !SSV[i].Size || (NextField % AsanAlignment) != 0) continue; Builder.CreateCall2( F, Builder.CreateAdd(ThisPtr, Builder.getIntN(PtrSize, EndOffset)), Builder.getIntN(PtrSize, PoisonSize)); } } /// EmitConstructorBody - Emits the body of the current constructor. void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { EmitAsanPrologueOrEpilogue(true); const CXXConstructorDecl *Ctor = cast(CurGD.getDecl()); CXXCtorType CtorType = CurGD.getCtorType(); assert((CGM.getTarget().getCXXABI().hasConstructorVariants() || CtorType == Ctor_Complete) && "can only generate complete ctor for this ABI"); // Before we go any further, try the complete->base constructor // delegation optimization. if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) && CGM.getTarget().getCXXABI().hasConstructorVariants()) { EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args, Ctor->getLocEnd()); return; } const FunctionDecl *Definition = 0; Stmt *Body = Ctor->getBody(Definition); assert(Definition == Ctor && "emitting wrong constructor body"); // Enter the function-try-block before the constructor prologue if // applicable. bool IsTryBody = (Body && isa(Body)); if (IsTryBody) EnterCXXTryStmt(*cast(Body), true); RegionCounter Cnt = getPGORegionCounter(Body); Cnt.beginRegion(Builder); RunCleanupsScope RunCleanups(*this); // TODO: in restricted cases, we can emit the vbase initializers of // a complete ctor and then delegate to the base ctor. // Emit the constructor prologue, i.e. the base and member // initializers. EmitCtorPrologue(Ctor, CtorType, Args); // Emit the body of the statement. if (IsTryBody) EmitStmt(cast(Body)->getTryBlock()); else if (Body) EmitStmt(Body); // Emit any cleanup blocks associated with the member or base // initializers, which includes (along the exceptional path) the // destructors for those members and bases that were fully // constructed. RunCleanups.ForceCleanup(); if (IsTryBody) ExitCXXTryStmt(*cast(Body), true); } namespace { /// RAII object to indicate that codegen is copying the value representation /// instead of the object representation. Useful when copying a struct or /// class which has uninitialized members and we're only performing /// lvalue-to-rvalue conversion on the object but not its members. class CopyingValueRepresentation { public: explicit CopyingValueRepresentation(CodeGenFunction &CGF) : CGF(CGF), OldSanOpts(CGF.SanOpts) { CGF.SanOpts.set(SanitizerKind::Bool, false); CGF.SanOpts.set(SanitizerKind::Enum, false); } ~CopyingValueRepresentation() { CGF.SanOpts = OldSanOpts; } private: CodeGenFunction &CGF; SanitizerSet OldSanOpts; }; } namespace { class FieldMemcpyizer { public: FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, const VarDecl *SrcRec) : CGF(CGF), ClassDecl(ClassDecl), SrcRec(SrcRec), RecLayout(CGF.getContext().getASTRecordLayout(ClassDecl)), FirstField(nullptr), LastField(nullptr), FirstFieldOffset(0), LastFieldOffset(0), LastAddedFieldIndex(0) {} bool isMemcpyableField(FieldDecl *F) const { // Never memcpy fields when we are adding poisoned paddings. if (CGF.getContext().getLangOpts().SanitizeAddressFieldPadding) return false; Qualifiers Qual = F->getType().getQualifiers(); if (Qual.hasVolatile() || Qual.hasObjCLifetime()) return false; return true; } void addMemcpyableField(FieldDecl *F) { if (!FirstField) addInitialField(F); else addNextField(F); } CharUnits getMemcpySize(uint64_t FirstByteOffset) const { unsigned LastFieldSize = LastField->isBitField() ? LastField->getBitWidthValue(CGF.getContext()) : CGF.getContext().getTypeSize(LastField->getType()); uint64_t MemcpySizeBits = LastFieldOffset + LastFieldSize - FirstByteOffset + CGF.getContext().getCharWidth() - 1; CharUnits MemcpySize = CGF.getContext().toCharUnitsFromBits(MemcpySizeBits); return MemcpySize; } void emitMemcpy() { // Give the subclass a chance to bail out if it feels the memcpy isn't // worth it (e.g. Hasn't aggregated enough data). if (!FirstField) { return; } CharUnits Alignment; uint64_t FirstByteOffset; if (FirstField->isBitField()) { const CGRecordLayout &RL = CGF.getTypes().getCGRecordLayout(FirstField->getParent()); const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField); Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment); // FirstFieldOffset is not appropriate for bitfields, // it won't tell us what the storage offset should be and thus might not // be properly aligned. // // Instead calculate the storage offset using the offset of the field in // the struct type. const llvm::DataLayout &DL = CGF.CGM.getDataLayout(); FirstByteOffset = DL.getStructLayout(RL.getLLVMType()) ->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField)); } else { Alignment = CGF.getContext().getDeclAlign(FirstField); FirstByteOffset = FirstFieldOffset; } assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) % Alignment) == 0 && "Bad field alignment."); CharUnits MemcpySize = getMemcpySize(FirstByteOffset); QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); llvm::Value *ThisPtr = CGF.LoadCXXThis(); LValue DestLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); LValue Dest = CGF.EmitLValueForFieldInitialization(DestLV, FirstField); llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(SrcRec)); LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField); emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(), Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(), MemcpySize, Alignment); reset(); } void reset() { FirstField = nullptr; } protected: CodeGenFunction &CGF; const CXXRecordDecl *ClassDecl; private: void emitMemcpyIR(llvm::Value *DestPtr, llvm::Value *SrcPtr, CharUnits Size, CharUnits Alignment) { llvm::PointerType *DPT = cast(DestPtr->getType()); llvm::Type *DBP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), DPT->getAddressSpace()); DestPtr = CGF.Builder.CreateBitCast(DestPtr, DBP); llvm::PointerType *SPT = cast(SrcPtr->getType()); llvm::Type *SBP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), SPT->getAddressSpace()); SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, SBP); CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity(), Alignment.getQuantity()); } void addInitialField(FieldDecl *F) { FirstField = F; LastField = F; FirstFieldOffset = RecLayout.getFieldOffset(F->getFieldIndex()); LastFieldOffset = FirstFieldOffset; LastAddedFieldIndex = F->getFieldIndex(); return; } void addNextField(FieldDecl *F) { // For the most part, the following invariant will hold: // F->getFieldIndex() == LastAddedFieldIndex + 1 // The one exception is that Sema won't add a copy-initializer for an // unnamed bitfield, which will show up here as a gap in the sequence. assert(F->getFieldIndex() >= LastAddedFieldIndex + 1 && "Cannot aggregate fields out of order."); LastAddedFieldIndex = F->getFieldIndex(); // The 'first' and 'last' fields are chosen by offset, rather than field // index. This allows the code to support bitfields, as well as regular // fields. uint64_t FOffset = RecLayout.getFieldOffset(F->getFieldIndex()); if (FOffset < FirstFieldOffset) { FirstField = F; FirstFieldOffset = FOffset; } else if (FOffset > LastFieldOffset) { LastField = F; LastFieldOffset = FOffset; } } const VarDecl *SrcRec; const ASTRecordLayout &RecLayout; FieldDecl *FirstField; FieldDecl *LastField; uint64_t FirstFieldOffset, LastFieldOffset; unsigned LastAddedFieldIndex; }; class ConstructorMemcpyizer : public FieldMemcpyizer { private: /// Get source argument for copy constructor. Returns null if not a copy /// constructor. static const VarDecl *getTrivialCopySource(CodeGenFunction &CGF, const CXXConstructorDecl *CD, FunctionArgList &Args) { if (CD->isCopyOrMoveConstructor() && CD->isDefaulted()) return Args[CGF.CGM.getCXXABI().getSrcArgforCopyCtor(CD, Args)]; return nullptr; } // Returns true if a CXXCtorInitializer represents a member initialization // that can be rolled into a memcpy. bool isMemberInitMemcpyable(CXXCtorInitializer *MemberInit) const { if (!MemcpyableCtor) return false; FieldDecl *Field = MemberInit->getMember(); assert(Field && "No field for member init."); QualType FieldType = Field->getType(); CXXConstructExpr *CE = dyn_cast(MemberInit->getInit()); // Bail out on non-POD, not-trivially-constructable members. if (!(CE && CE->getConstructor()->isTrivial()) && !(FieldType.isTriviallyCopyableType(CGF.getContext()) || FieldType->isReferenceType())) return false; // Bail out on volatile fields. if (!isMemcpyableField(Field)) return false; // Otherwise we're good. return true; } public: ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD, FunctionArgList &Args) : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CGF, CD, Args)), ConstructorDecl(CD), MemcpyableCtor(CD->isDefaulted() && CD->isCopyOrMoveConstructor() && CGF.getLangOpts().getGC() == LangOptions::NonGC), Args(Args) { } void addMemberInitializer(CXXCtorInitializer *MemberInit) { if (isMemberInitMemcpyable(MemberInit)) { AggregatedInits.push_back(MemberInit); addMemcpyableField(MemberInit->getMember()); } else { emitAggregatedInits(); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), MemberInit, ConstructorDecl, Args); } } void emitAggregatedInits() { if (AggregatedInits.size() <= 1) { // This memcpy is too small to be worthwhile. Fall back on default // codegen. if (!AggregatedInits.empty()) { CopyingValueRepresentation CVR(CGF); EmitMemberInitializer(CGF, ConstructorDecl->getParent(), AggregatedInits[0], ConstructorDecl, Args); } reset(); return; } pushEHDestructors(); emitMemcpy(); AggregatedInits.clear(); } void pushEHDestructors() { llvm::Value *ThisPtr = CGF.LoadCXXThis(); QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl); LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy); for (unsigned i = 0; i < AggregatedInits.size(); ++i) { QualType FieldType = AggregatedInits[i]->getMember()->getType(); QualType::DestructionKind dtorKind = FieldType.isDestructedType(); if (CGF.needsEHCleanup(dtorKind)) CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); } } void finish() { emitAggregatedInits(); } private: const CXXConstructorDecl *ConstructorDecl; bool MemcpyableCtor; FunctionArgList &Args; SmallVector AggregatedInits; }; class AssignmentMemcpyizer : public FieldMemcpyizer { private: // Returns the memcpyable field copied by the given statement, if one // exists. Otherwise returns null. FieldDecl *getMemcpyableField(Stmt *S) { if (!AssignmentsMemcpyable) return nullptr; if (BinaryOperator *BO = dyn_cast(S)) { // Recognise trivial assignments. if (BO->getOpcode() != BO_Assign) return nullptr; MemberExpr *ME = dyn_cast(BO->getLHS()); if (!ME) return nullptr; FieldDecl *Field = dyn_cast(ME->getMemberDecl()); if (!Field || !isMemcpyableField(Field)) return nullptr; Stmt *RHS = BO->getRHS(); if (ImplicitCastExpr *EC = dyn_cast(RHS)) RHS = EC->getSubExpr(); if (!RHS) return nullptr; MemberExpr *ME2 = dyn_cast(RHS); if (dyn_cast(ME2->getMemberDecl()) != Field) return nullptr; return Field; } else if (CXXMemberCallExpr *MCE = dyn_cast(S)) { CXXMethodDecl *MD = dyn_cast(MCE->getCalleeDecl()); if (!(MD && (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) && MD->isTrivial())) return nullptr; MemberExpr *IOA = dyn_cast(MCE->getImplicitObjectArgument()); if (!IOA) return nullptr; FieldDecl *Field = dyn_cast(IOA->getMemberDecl()); if (!Field || !isMemcpyableField(Field)) return nullptr; MemberExpr *Arg0 = dyn_cast(MCE->getArg(0)); if (!Arg0 || Field != dyn_cast(Arg0->getMemberDecl())) return nullptr; return Field; } else if (CallExpr *CE = dyn_cast(S)) { FunctionDecl *FD = dyn_cast(CE->getCalleeDecl()); if (!FD || FD->getBuiltinID() != Builtin::BI__builtin_memcpy) return nullptr; Expr *DstPtr = CE->getArg(0); if (ImplicitCastExpr *DC = dyn_cast(DstPtr)) DstPtr = DC->getSubExpr(); UnaryOperator *DUO = dyn_cast(DstPtr); if (!DUO || DUO->getOpcode() != UO_AddrOf) return nullptr; MemberExpr *ME = dyn_cast(DUO->getSubExpr()); if (!ME) return nullptr; FieldDecl *Field = dyn_cast(ME->getMemberDecl()); if (!Field || !isMemcpyableField(Field)) return nullptr; Expr *SrcPtr = CE->getArg(1); if (ImplicitCastExpr *SC = dyn_cast(SrcPtr)) SrcPtr = SC->getSubExpr(); UnaryOperator *SUO = dyn_cast(SrcPtr); if (!SUO || SUO->getOpcode() != UO_AddrOf) return nullptr; MemberExpr *ME2 = dyn_cast(SUO->getSubExpr()); if (!ME2 || Field != dyn_cast(ME2->getMemberDecl())) return nullptr; return Field; } return nullptr; } bool AssignmentsMemcpyable; SmallVector AggregatedStmts; public: AssignmentMemcpyizer(CodeGenFunction &CGF, const CXXMethodDecl *AD, FunctionArgList &Args) : FieldMemcpyizer(CGF, AD->getParent(), Args[Args.size() - 1]), AssignmentsMemcpyable(CGF.getLangOpts().getGC() == LangOptions::NonGC) { assert(Args.size() == 2); } void emitAssignment(Stmt *S) { FieldDecl *F = getMemcpyableField(S); if (F) { addMemcpyableField(F); AggregatedStmts.push_back(S); } else { emitAggregatedStmts(); CGF.EmitStmt(S); } } void emitAggregatedStmts() { if (AggregatedStmts.size() <= 1) { if (!AggregatedStmts.empty()) { CopyingValueRepresentation CVR(CGF); CGF.EmitStmt(AggregatedStmts[0]); } reset(); } emitMemcpy(); AggregatedStmts.clear(); } void finish() { emitAggregatedStmts(); } }; } /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType CtorType, FunctionArgList &Args) { if (CD->isDelegatingConstructor()) return EmitDelegatingCXXConstructorCall(CD, Args); const CXXRecordDecl *ClassDecl = CD->getParent(); CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); llvm::BasicBlock *BaseCtorContinueBB = nullptr; if (ClassDecl->getNumVBases() && !CGM.getTarget().getCXXABI().hasConstructorVariants()) { // The ABIs that don't have constructor variants need to put a branch // before the virtual base initialization code. BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this, ClassDecl); assert(BaseCtorContinueBB); } // Virtual base initializers first. for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) { EmitBaseInitializer(*this, ClassDecl, *B, CtorType); } if (BaseCtorContinueBB) { // Complete object handler should continue to the remaining initializers. Builder.CreateBr(BaseCtorContinueBB); EmitBlock(BaseCtorContinueBB); } // Then, non-virtual base initializers. for (; B != E && (*B)->isBaseInitializer(); B++) { assert(!(*B)->isBaseVirtual()); EmitBaseInitializer(*this, ClassDecl, *B, CtorType); } InitializeVTablePointers(ClassDecl); // And finally, initialize class members. FieldConstructionScope FCS(*this, CXXThisValue); ConstructorMemcpyizer CM(*this, CD, Args); for (; B != E; B++) { CXXCtorInitializer *Member = (*B); assert(!Member->isBaseInitializer()); assert(Member->isAnyMemberInitializer() && "Delegating initializer on non-delegating constructor"); CM.addMemberInitializer(Member); } CM.finish(); } static bool FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field); static bool HasTrivialDestructorBody(ASTContext &Context, const CXXRecordDecl *BaseClassDecl, const CXXRecordDecl *MostDerivedClassDecl) { // If the destructor is trivial we don't have to check anything else. if (BaseClassDecl->hasTrivialDestructor()) return true; if (!BaseClassDecl->getDestructor()->hasTrivialBody()) return false; // Check fields. for (const auto *Field : BaseClassDecl->fields()) if (!FieldHasTrivialDestructorBody(Context, Field)) return false; // Check non-virtual bases. for (const auto &I : BaseClassDecl->bases()) { if (I.isVirtual()) continue; const CXXRecordDecl *NonVirtualBase = cast(I.getType()->castAs()->getDecl()); if (!HasTrivialDestructorBody(Context, NonVirtualBase, MostDerivedClassDecl)) return false; } if (BaseClassDecl == MostDerivedClassDecl) { // Check virtual bases. for (const auto &I : BaseClassDecl->vbases()) { const CXXRecordDecl *VirtualBase = cast(I.getType()->castAs()->getDecl()); if (!HasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl)) return false; } } return true; } static bool FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field) { QualType FieldBaseElementType = Context.getBaseElementType(Field->getType()); const RecordType *RT = FieldBaseElementType->getAs(); if (!RT) return true; CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl); } /// CanSkipVTablePointerInitialization - Check whether we need to initialize /// any vtable pointers before calling this destructor. static bool CanSkipVTablePointerInitialization(ASTContext &Context, const CXXDestructorDecl *Dtor) { if (!Dtor->hasTrivialBody()) return false; // Check the fields. const CXXRecordDecl *ClassDecl = Dtor->getParent(); for (const auto *Field : ClassDecl->fields()) if (!FieldHasTrivialDestructorBody(Context, Field)) return false; return true; } /// EmitDestructorBody - Emits the body of the current destructor. void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast(CurGD.getDecl()); CXXDtorType DtorType = CurGD.getDtorType(); // The call to operator delete in a deleting destructor happens // outside of the function-try-block, which means it's always // possible to delegate the destructor body to the complete // destructor. Do so. if (DtorType == Dtor_Deleting) { EnterDtorCleanups(Dtor, Dtor_Deleting); EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, /*Delegating=*/false, LoadCXXThis()); PopCleanupBlock(); return; } Stmt *Body = Dtor->getBody(); // If the body is a function-try-block, enter the try before // anything else. bool isTryBody = (Body && isa(Body)); if (isTryBody) EnterCXXTryStmt(*cast(Body), true); EmitAsanPrologueOrEpilogue(false); // Enter the epilogue cleanups. RunCleanupsScope DtorEpilogue(*this); // If this is the complete variant, just invoke the base variant; // the epilogue will destruct the virtual bases. But we can't do // this optimization if the body is a function-try-block, because // we'd introduce *two* handler blocks. In the Microsoft ABI, we // always delegate because we might not have a definition in this TU. switch (DtorType) { case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT"); case Dtor_Deleting: llvm_unreachable("already handled deleting case"); case Dtor_Complete: assert((Body || getTarget().getCXXABI().isMicrosoft()) && "can't emit a dtor without a body for non-Microsoft ABIs"); // Enter the cleanup scopes for virtual bases. EnterDtorCleanups(Dtor, Dtor_Complete); if (!isTryBody) { EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, /*Delegating=*/false, LoadCXXThis()); break; } // Fallthrough: act like we're in the base variant. case Dtor_Base: assert(Body); RegionCounter Cnt = getPGORegionCounter(Body); Cnt.beginRegion(Builder); // Enter the cleanup scopes for fields and non-virtual bases. EnterDtorCleanups(Dtor, Dtor_Base); // Initialize the vtable pointers before entering the body. if (!CanSkipVTablePointerInitialization(getContext(), Dtor)) InitializeVTablePointers(Dtor->getParent()); if (isTryBody) EmitStmt(cast(Body)->getTryBlock()); else if (Body) EmitStmt(Body); else { assert(Dtor->isImplicit() && "bodyless dtor not implicit"); // nothing to do besides what's in the epilogue } // -fapple-kext must inline any call to this dtor into // the caller's body. if (getLangOpts().AppleKext) CurFn->addFnAttr(llvm::Attribute::AlwaysInline); break; } // Jump out through the epilogue cleanups. DtorEpilogue.ForceCleanup(); // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast(Body), true); } void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) { const CXXMethodDecl *AssignOp = cast(CurGD.getDecl()); const Stmt *RootS = AssignOp->getBody(); assert(isa(RootS) && "Body of an implicit assignment operator should be compound stmt."); const CompoundStmt *RootCS = cast(RootS); LexicalScope Scope(*this, RootCS->getSourceRange()); AssignmentMemcpyizer AM(*this, AssignOp, Args); for (auto *I : RootCS->body()) AM.emitAssignment(I); AM.finish(); } namespace { /// Call the operator delete associated with the current destructor. struct CallDtorDelete : EHScopeStack::Cleanup { CallDtorDelete() {} void Emit(CodeGenFunction &CGF, Flags flags) override { const CXXDestructorDecl *Dtor = cast(CGF.CurCodeDecl); const CXXRecordDecl *ClassDecl = Dtor->getParent(); CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), CGF.getContext().getTagDeclType(ClassDecl)); } }; struct CallDtorDeleteConditional : EHScopeStack::Cleanup { llvm::Value *ShouldDeleteCondition; public: CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition) : ShouldDeleteCondition(ShouldDeleteCondition) { assert(ShouldDeleteCondition != nullptr); } void Emit(CodeGenFunction &CGF, Flags flags) override { llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete"); llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue"); llvm::Value *ShouldCallDelete = CGF.Builder.CreateIsNull(ShouldDeleteCondition); CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB); CGF.EmitBlock(callDeleteBB); const CXXDestructorDecl *Dtor = cast(CGF.CurCodeDecl); const CXXRecordDecl *ClassDecl = Dtor->getParent(); CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), CGF.getContext().getTagDeclType(ClassDecl)); CGF.Builder.CreateBr(continueBB); CGF.EmitBlock(continueBB); } }; class DestroyField : public EHScopeStack::Cleanup { const FieldDecl *field; CodeGenFunction::Destroyer *destroyer; bool useEHCleanupForArray; public: DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer, bool useEHCleanupForArray) : field(field), destroyer(destroyer), useEHCleanupForArray(useEHCleanupForArray) {} void Emit(CodeGenFunction &CGF, Flags flags) override { // Find the address of the field. llvm::Value *thisValue = CGF.LoadCXXThis(); QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent()); LValue ThisLV = CGF.MakeAddrLValue(thisValue, RecordTy); LValue LV = CGF.EmitLValueForField(ThisLV, field); assert(LV.isSimple()); CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer, flags.isForNormalCleanup() && useEHCleanupForArray); } }; } /// \brief Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, CXXDtorType DtorType) { assert((!DD->isTrivial() || DD->hasAttr()) && "Should not emit dtor epilogue for non-exported trivial dtor!"); // The deleting-destructor phase just needs to call the appropriate // operator delete that Sema picked up. if (DtorType == Dtor_Deleting) { assert(DD->getOperatorDelete() && "operator delete missing - EnterDtorCleanups"); if (CXXStructorImplicitParamValue) { // If there is an implicit param to the deleting dtor, it's a boolean // telling whether we should call delete at the end of the dtor. EHStack.pushCleanup( NormalAndEHCleanup, CXXStructorImplicitParamValue); } else { EHStack.pushCleanup(NormalAndEHCleanup); } return; } const CXXRecordDecl *ClassDecl = DD->getParent(); // Unions have no bases and do not call field destructors. if (ClassDecl->isUnion()) return; // The complete-destructor phase just destructs all the virtual bases. if (DtorType == Dtor_Complete) { // We push them in the forward order so that they'll be popped in // the reverse order. for (const auto &Base : ClassDecl->vbases()) { CXXRecordDecl *BaseClassDecl = cast(Base.getType()->getAs()->getDecl()); // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; EHStack.pushCleanup(NormalAndEHCleanup, BaseClassDecl, /*BaseIsVirtual*/ true); } return; } assert(DtorType == Dtor_Base); // Destroy non-virtual bases. for (const auto &Base : ClassDecl->bases()) { // Ignore virtual bases. if (Base.isVirtual()) continue; CXXRecordDecl *BaseClassDecl = Base.getType()->getAsCXXRecordDecl(); // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; EHStack.pushCleanup(NormalAndEHCleanup, BaseClassDecl, /*BaseIsVirtual*/ false); } // Destroy direct fields. for (const auto *Field : ClassDecl->fields()) { QualType type = Field->getType(); QualType::DestructionKind dtorKind = type.isDestructedType(); if (!dtorKind) continue; // Anonymous union members do not have their destructors called. const RecordType *RT = type->getAsUnionType(); if (RT && RT->getDecl()->isAnonymousStructOrUnion()) continue; CleanupKind cleanupKind = getCleanupKind(dtorKind); EHStack.pushCleanup(cleanupKind, Field, getDestroyer(dtorKind), cleanupKind & EHCleanup); } } /// EmitCXXAggrConstructorCall - Emit a loop to call a particular /// constructor for each of several members of an array. /// /// \param ctor the constructor to call for each element /// \param arrayType the type of the array to initialize /// \param arrayBegin an arrayType* /// \param zeroInitialize true if each element should be /// zero-initialized before it is constructed void CodeGenFunction::EmitCXXAggrConstructorCall( const CXXConstructorDecl *ctor, const ConstantArrayType *arrayType, llvm::Value *arrayBegin, const CXXConstructExpr *E, bool zeroInitialize) { QualType elementType; llvm::Value *numElements = emitArrayLength(arrayType, elementType, arrayBegin); EmitCXXAggrConstructorCall(ctor, numElements, arrayBegin, E, zeroInitialize); } /// EmitCXXAggrConstructorCall - Emit a loop to call a particular /// constructor for each of several members of an array. /// /// \param ctor the constructor to call for each element /// \param numElements the number of elements in the array; /// may be zero /// \param arrayBegin a T*, where T is the type constructed by ctor /// \param zeroInitialize true if each element should be /// zero-initialized before it is constructed void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, llvm::Value *numElements, llvm::Value *arrayBegin, const CXXConstructExpr *E, bool zeroInitialize) { // It's legal for numElements to be zero. This can happen both // dynamically, because x can be zero in 'new A[x]', and statically, // because of GCC extensions that permit zero-length arrays. There // are probably legitimate places where we could assume that this // doesn't happen, but it's not clear that it's worth it. llvm::BranchInst *zeroCheckBranch = nullptr; // Optimize for a constant count. llvm::ConstantInt *constantCount = dyn_cast(numElements); if (constantCount) { // Just skip out if the constant count is zero. if (constantCount->isZero()) return; // Otherwise, emit the check. } else { llvm::BasicBlock *loopBB = createBasicBlock("new.ctorloop"); llvm::Value *iszero = Builder.CreateIsNull(numElements, "isempty"); zeroCheckBranch = Builder.CreateCondBr(iszero, loopBB, loopBB); EmitBlock(loopBB); } // Find the end of the array. llvm::Value *arrayEnd = Builder.CreateInBoundsGEP(arrayBegin, numElements, "arrayctor.end"); // Enter the loop, setting up a phi for the current location to initialize. llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); llvm::BasicBlock *loopBB = createBasicBlock("arrayctor.loop"); EmitBlock(loopBB); llvm::PHINode *cur = Builder.CreatePHI(arrayBegin->getType(), 2, "arrayctor.cur"); cur->addIncoming(arrayBegin, entryBB); // Inside the loop body, emit the constructor call on the array element. QualType type = getContext().getTypeDeclType(ctor->getParent()); // Zero initialize the storage, if requested. if (zeroInitialize) EmitNullInitialization(cur, type); // C++ [class.temporary]p4: // There are two contexts in which temporaries are destroyed at a different // point than the end of the full-expression. The first context is when a // default constructor is called to initialize an element of an array. // If the constructor has one or more default arguments, the destruction of // every temporary created in a default argument expression is sequenced // before the construction of the next array element, if any. { RunCleanupsScope Scope(*this); // Evaluate the constructor and its arguments in a regular // partial-destroy cleanup. if (getLangOpts().Exceptions && !ctor->getParent()->hasTrivialDestructor()) { Destroyer *destroyer = destroyCXXObject; pushRegularPartialArrayCleanup(arrayBegin, cur, type, *destroyer); } EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/false, /*Delegating=*/false, cur, E); } // Go to the next element. llvm::Value *next = Builder.CreateInBoundsGEP(cur, llvm::ConstantInt::get(SizeTy, 1), "arrayctor.next"); cur->addIncoming(next, Builder.GetInsertBlock()); // Check whether that's the end of the loop. llvm::Value *done = Builder.CreateICmpEQ(next, arrayEnd, "arrayctor.done"); llvm::BasicBlock *contBB = createBasicBlock("arrayctor.cont"); Builder.CreateCondBr(done, contBB, loopBB); // Patch the earlier check to skip over the loop. if (zeroCheckBranch) zeroCheckBranch->setSuccessor(0, contBB); EmitBlock(contBB); } void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { const RecordType *rtype = type->castAs(); const CXXRecordDecl *record = cast(rtype->getDecl()); const CXXDestructorDecl *dtor = record->getDestructor(); assert(!dtor->isTrivial()); CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false, /*Delegating=*/false, addr); } void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, llvm::Value *This, const CXXConstructExpr *E) { // If this is a trivial constructor, just emit what's needed. if (D->isTrivial() && !D->getParent()->mayInsertExtraPadding()) { if (E->getNumArgs() == 0) { // Trivial default constructor, no codegen required. assert(D->isDefaultConstructor() && "trivial 0-arg ctor not a default ctor"); return; } assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor"); assert(D->isCopyOrMoveConstructor() && "trivial 1-arg ctor not a copy/move ctor"); const Expr *Arg = E->getArg(0); QualType Ty = Arg->getType(); llvm::Value *Src = EmitLValue(Arg).getAddress(); EmitAggregateCopy(This, Src, Ty); return; } // C++11 [class.mfct.non-static]p2: // If a non-static member function of a class X is called for an object that // is not of type X, or of a type derived from X, the behavior is undefined. // FIXME: Provide a source location here. EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, SourceLocation(), This, getContext().getRecordType(D->getParent())); CallArgList Args; // Push the this ptr. Args.add(RValue::get(This), D->getThisType(getContext())); // Add the rest of the user-supplied arguments. const FunctionProtoType *FPT = D->getType()->castAs(); EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end(), E->getConstructor()); // Insert any ABI-specific implicit constructor arguments. unsigned ExtraArgs = CGM.getCXXABI().addImplicitConstructorArgs( *this, D, Type, ForVirtualBase, Delegating, Args); // Emit the call. llvm::Value *Callee = CGM.getAddrOfCXXStructor(D, getFromCtorType(Type)); const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(Args, D, Type, ExtraArgs); EmitCall(Info, Callee, ReturnValueSlot(), Args, D); } void CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, llvm::Value *This, llvm::Value *Src, const CXXConstructExpr *E) { if (D->isTrivial() && !D->getParent()->mayInsertExtraPadding()) { assert(E->getNumArgs() == 1 && "unexpected argcount for trivial ctor"); assert(D->isCopyOrMoveConstructor() && "trivial 1-arg ctor not a copy/move ctor"); EmitAggregateCopy(This, Src, E->arg_begin()->getType()); return; } llvm::Value *Callee = CGM.getAddrOfCXXStructor(D, StructorType::Complete); assert(D->isInstance() && "Trying to emit a member call expr on a static method!"); const FunctionProtoType *FPT = D->getType()->castAs(); CallArgList Args; // Push the this ptr. Args.add(RValue::get(This), D->getThisType(getContext())); // Push the src ptr. QualType QT = *(FPT->param_type_begin()); llvm::Type *t = CGM.getTypes().ConvertType(QT); Src = Builder.CreateBitCast(Src, t); Args.add(RValue::get(Src), QT); // Skip over first argument (Src). EmitCallArgs(Args, FPT, E->arg_begin() + 1, E->arg_end(), E->getConstructor(), /*ParamsToSkip*/ 1); EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, RequiredArgs::All), Callee, ReturnValueSlot(), Args, D); } void CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args, SourceLocation Loc) { CallArgList DelegateArgs; FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); assert(I != E && "no parameters to constructor"); // this DelegateArgs.add(RValue::get(LoadCXXThis()), (*I)->getType()); ++I; // vtt if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType), /*ForVirtualBase=*/false, /*Delegating=*/true)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); DelegateArgs.add(RValue::get(VTT), VoidPP); if (CGM.getCXXABI().NeedsVTTParameter(CurGD)) { assert(I != E && "cannot skip vtt parameter, already done with args"); assert((*I)->getType() == VoidPP && "skipping parameter not of vtt type"); ++I; } } // Explicit arguments. for (; I != E; ++I) { const VarDecl *param = *I; // FIXME: per-argument source location EmitDelegateCallArg(DelegateArgs, param, Loc); } llvm::Value *Callee = CGM.getAddrOfCXXStructor(Ctor, getFromCtorType(CtorType)); EmitCall(CGM.getTypes() .arrangeCXXStructorDeclaration(Ctor, getFromCtorType(CtorType)), Callee, ReturnValueSlot(), DelegateArgs, Ctor); } namespace { struct CallDelegatingCtorDtor : EHScopeStack::Cleanup { const CXXDestructorDecl *Dtor; llvm::Value *Addr; CXXDtorType Type; CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr, CXXDtorType Type) : Dtor(D), Addr(Addr), Type(Type) {} void Emit(CodeGenFunction &CGF, Flags flags) override { CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false, /*Delegating=*/true, Addr); } }; } void CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, const FunctionArgList &Args) { assert(Ctor->isDelegatingConstructor()); llvm::Value *ThisPtr = LoadCXXThis(); QualType Ty = getContext().getTagDeclType(Ctor->getParent()); CharUnits Alignment = getContext().getTypeAlignInChars(Ty); AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, Alignment, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); const CXXRecordDecl *ClassDecl = Ctor->getParent(); if (CGM.getLangOpts().Exceptions && !ClassDecl->hasTrivialDestructor()) { CXXDtorType Type = CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base; EHStack.pushCleanup(EHCleanup, ClassDecl->getDestructor(), ThisPtr, Type); } } void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, bool ForVirtualBase, bool Delegating, llvm::Value *This) { CGM.getCXXABI().EmitDestructorCall(*this, DD, Type, ForVirtualBase, Delegating, This); } namespace { struct CallLocalDtor : EHScopeStack::Cleanup { const CXXDestructorDecl *Dtor; llvm::Value *Addr; CallLocalDtor(const CXXDestructorDecl *D, llvm::Value *Addr) : Dtor(D), Addr(Addr) {} void Emit(CodeGenFunction &CGF, Flags flags) override { CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, /*Delegating=*/false, Addr); } }; } void CodeGenFunction::PushDestructorCleanup(const CXXDestructorDecl *D, llvm::Value *Addr) { EHStack.pushCleanup(NormalAndEHCleanup, D, Addr); } void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) { CXXRecordDecl *ClassDecl = T->getAsCXXRecordDecl(); if (!ClassDecl) return; if (ClassDecl->hasTrivialDestructor()) return; const CXXDestructorDecl *D = ClassDecl->getDestructor(); assert(D && D->isUsed() && "destructor not marked as used!"); PushDestructorCleanup(D, Addr); } void CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, const CXXRecordDecl *NearestVBase, CharUnits OffsetFromNearestVBase, const CXXRecordDecl *VTableClass) { // Compute the address point. bool NeedsVirtualOffset; llvm::Value *VTableAddressPoint = CGM.getCXXABI().getVTableAddressPointInStructor( *this, VTableClass, Base, NearestVBase, NeedsVirtualOffset); if (!VTableAddressPoint) return; // Compute where to store the address point. llvm::Value *VirtualOffset = nullptr; CharUnits NonVirtualOffset = CharUnits::Zero(); if (NeedsVirtualOffset) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. VirtualOffset = CGM.getCXXABI().GetVirtualBaseClassOffset(*this, LoadCXXThis(), VTableClass, NearestVBase); NonVirtualOffset = OffsetFromNearestVBase; } else { // We can just use the base offset in the complete class. NonVirtualOffset = Base.getBaseOffset(); } // Apply the offsets. llvm::Value *VTableField = LoadCXXThis(); if (!NonVirtualOffset.isZero() || VirtualOffset) VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField, NonVirtualOffset, VirtualOffset); // Finally, store the address point. Use the same LLVM types as the field to // support optimization. llvm::Type *VTablePtrTy = llvm::FunctionType::get(CGM.Int32Ty, /*isVarArg=*/true) ->getPointerTo() ->getPointerTo(); VTableField = Builder.CreateBitCast(VTableField, VTablePtrTy->getPointerTo()); VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy); llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField); CGM.DecorateInstruction(Store, CGM.getTBAAInfoForVTablePtr()); } void CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase, CharUnits OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, const CXXRecordDecl *VTableClass, VisitedVirtualBasesSetTy& VBases) { // If this base is a non-virtual primary base the address point has already // been set. if (!BaseIsNonVirtualPrimaryBase) { // Initialize the vtable pointer for this base. InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase, VTableClass); } const CXXRecordDecl *RD = Base.getBase(); // Traverse bases. for (const auto &I : RD->bases()) { CXXRecordDecl *BaseDecl = cast(I.getType()->getAs()->getDecl()); // Ignore classes without a vtable. if (!BaseDecl->isDynamicClass()) continue; CharUnits BaseOffset; CharUnits BaseOffsetFromNearestVBase; bool BaseDeclIsNonVirtualPrimaryBase; if (I.isVirtual()) { // Check if we've visited this virtual base before. if (!VBases.insert(BaseDecl).second) continue; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(VTableClass); BaseOffset = Layout.getVBaseClassOffset(BaseDecl); BaseOffsetFromNearestVBase = CharUnits::Zero(); BaseDeclIsNonVirtualPrimaryBase = false; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); BaseOffsetFromNearestVBase = OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl); BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; } InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset), I.isVirtual() ? BaseDecl : NearestVBase, BaseOffsetFromNearestVBase, BaseDeclIsNonVirtualPrimaryBase, VTableClass, VBases); } } void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { // Ignore classes without a vtable. if (!RD->isDynamicClass()) return; // Initialize the vtable pointers for this class and all of its bases. VisitedVirtualBasesSetTy VBases; InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()), /*NearestVBase=*/nullptr, /*OffsetFromNearestVBase=*/CharUnits::Zero(), /*BaseIsNonVirtualPrimaryBase=*/false, RD, VBases); if (RD->getNumVBases()) CGM.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, RD); } llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This, llvm::Type *Ty) { llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo()); llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable"); CGM.DecorateInstruction(VTable, CGM.getTBAAInfoForVTablePtr()); return VTable; } // FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do // quite what we want. static const Expr *skipNoOpCastsAndParens(const Expr *E) { while (true) { if (const ParenExpr *PE = dyn_cast(E)) { E = PE->getSubExpr(); continue; } if (const CastExpr *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_NoOp) { E = CE->getSubExpr(); continue; } } if (const UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_Extension) { E = UO->getSubExpr(); continue; } } return E; } } bool CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, const CXXMethodDecl *MD) { // When building with -fapple-kext, all calls must go through the vtable since // the kernel linker can do runtime patching of vtables. if (getLangOpts().AppleKext) return false; // If the most derived class is marked final, we know that no subclass can // override this member function and so we can devirtualize it. For example: // // struct A { virtual void f(); } // struct B final : A { }; // // void f(B *b) { // b->f(); // } // const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); if (MostDerivedClassDecl->hasAttr()) return true; // If the member function is marked 'final', we know that it can't be // overridden and can therefore devirtualize it. if (MD->hasAttr()) return true; // Similarly, if the class itself is marked 'final' it can't be overridden // and we can therefore devirtualize the member function call. if (MD->getParent()->hasAttr()) return true; Base = skipNoOpCastsAndParens(Base); if (const DeclRefExpr *DRE = dyn_cast(Base)) { if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { // This is a record decl. We know the type and can devirtualize it. return VD->getType()->isRecordType(); } return false; } // We can devirtualize calls on an object accessed by a class member access // expression, since by C++11 [basic.life]p6 we know that it can't refer to // a derived class object constructed in the same location. if (const MemberExpr *ME = dyn_cast(Base)) if (const ValueDecl *VD = dyn_cast(ME->getMemberDecl())) return VD->getType()->isRecordType(); // We can always devirtualize calls on temporary object expressions. if (isa(Base)) return true; // And calls on bound temporaries. if (isa(Base)) return true; // Check if this is a call expr that returns a record type. if (const CallExpr *CE = dyn_cast(Base)) return CE->getCallReturnType()->isRecordType(); // We can't devirtualize the call. return false; } void CodeGenFunction::EmitForwardingCallToLambda( const CXXMethodDecl *callOperator, CallArgList &callArgs) { // Get the address of the call operator. const CGFunctionInfo &calleeFnInfo = CGM.getTypes().arrangeCXXMethodDeclaration(callOperator); llvm::Value *callee = CGM.GetAddrOfFunction(GlobalDecl(callOperator), CGM.getTypes().GetFunctionType(calleeFnInfo)); // Prepare the return slot. const FunctionProtoType *FPT = callOperator->getType()->castAs(); QualType resultType = FPT->getReturnType(); ReturnValueSlot returnSlot; if (!resultType->isVoidType() && calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect && !hasScalarEvaluationKind(calleeFnInfo.getReturnType())) returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified()); // We don't need to separately arrange the call arguments because // the call can't be variadic anyway --- it's impossible to forward // variadic arguments. // Now emit our call. RValue RV = EmitCall(calleeFnInfo, callee, returnSlot, callArgs, callOperator); // If necessary, copy the returned value into the slot. if (!resultType->isVoidType() && returnSlot.isNull()) EmitReturnOfRValue(RV, resultType); else EmitBranchThroughCleanup(ReturnBlock); } void CodeGenFunction::EmitLambdaBlockInvokeBody() { const BlockDecl *BD = BlockInfo->getBlockDecl(); const VarDecl *variable = BD->capture_begin()->getVariable(); const CXXRecordDecl *Lambda = variable->getType()->getAsCXXRecordDecl(); // Start building arguments for forwarding call CallArgList CallArgs; QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda)); llvm::Value *ThisPtr = GetAddrOfBlockDecl(variable, false); CallArgs.add(RValue::get(ThisPtr), ThisType); // Add the rest of the parameters. for (auto param : BD->params()) EmitDelegateCallArg(CallArgs, param, param->getLocStart()); assert(!Lambda->isGenericLambda() && "generic lambda interconversion to block not implemented"); EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs); } void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { if (cast(CurCodeDecl)->isVariadic()) { // FIXME: Making this work correctly is nasty because it requires either // cloning the body of the call operator or making the call operator forward. CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function"); return; } EmitFunctionBody(Args, cast(CurGD.getDecl())->getBody()); } void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { const CXXRecordDecl *Lambda = MD->getParent(); // Start building arguments for forwarding call CallArgList CallArgs; QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda)); llvm::Value *ThisPtr = llvm::UndefValue::get(getTypes().ConvertType(ThisType)); CallArgs.add(RValue::get(ThisPtr), ThisType); // Add the rest of the parameters. for (auto Param : MD->params()) EmitDelegateCallArg(CallArgs, Param, Param->getLocStart()); const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); // For a generic lambda, find the corresponding call operator specialization // to which the call to the static-invoker shall be forwarded. if (Lambda->isGenericLambda()) { assert(MD->isFunctionTemplateSpecialization()); const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs(); FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate(); void *InsertPos = nullptr; FunctionDecl *CorrespondingCallOpSpecialization = CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos); assert(CorrespondingCallOpSpecialization); CallOp = cast(CorrespondingCallOpSpecialization); } EmitForwardingCallToLambda(CallOp, CallArgs); } void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) { if (MD->isVariadic()) { // FIXME: Making this work correctly is nasty because it requires either // cloning the body of the call operator or making the call operator forward. CGM.ErrorUnsupported(MD, "lambda conversion to variadic function"); return; } EmitLambdaDelegatingInvokeBody(MD); } Index: vendor/clang/dist/lib/CodeGen/CGExprScalar.cpp =================================================================== --- vendor/clang/dist/lib/CodeGen/CGExprScalar.cpp (revision 278753) +++ vendor/clang/dist/lib/CodeGen/CGExprScalar.cpp (revision 278754) @@ -1,3508 +1,3509 @@ //===--- CGExprScalar.cpp - Emit LLVM Code for Scalar Exprs ---------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code to emit Expr nodes with scalar LLVM types as LLVM code. // //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include using namespace clang; using namespace CodeGen; using llvm::Value; //===----------------------------------------------------------------------===// // Scalar Expression Emitter //===----------------------------------------------------------------------===// namespace { struct BinOpInfo { Value *LHS; Value *RHS; QualType Ty; // Computation Type. BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform bool FPContractable; const Expr *E; // Entire expr, for error unsupported. May not be binop. }; static bool MustVisitNullValue(const Expr *E) { // If a null pointer expression's type is the C++0x nullptr_t, then // it's not necessarily a simple constant and it must be evaluated // for its potential side effects. return E->getType()->isNullPtrType(); } class ScalarExprEmitter : public StmtVisitor { CodeGenFunction &CGF; CGBuilderTy &Builder; bool IgnoreResultAssign; llvm::LLVMContext &VMContext; public: ScalarExprEmitter(CodeGenFunction &cgf, bool ira=false) : CGF(cgf), Builder(CGF.Builder), IgnoreResultAssign(ira), VMContext(cgf.getLLVMContext()) { } //===--------------------------------------------------------------------===// // Utilities //===--------------------------------------------------------------------===// bool TestAndClearIgnoreResultAssign() { bool I = IgnoreResultAssign; IgnoreResultAssign = false; return I; } llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::TypeCheckKind TCK) { return CGF.EmitCheckedLValue(E, TCK); } void EmitBinOpCheck(ArrayRef> Checks, const BinOpInfo &Info); Value *EmitLoadOfLValue(LValue LV, SourceLocation Loc) { return CGF.EmitLoadOfLValue(LV, Loc).getScalarVal(); } void EmitLValueAlignmentAssumption(const Expr *E, Value *V) { const AlignValueAttr *AVAttr = nullptr; if (const auto *DRE = dyn_cast(E)) { const ValueDecl *VD = DRE->getDecl(); if (VD->getType()->isReferenceType()) { if (const auto *TTy = dyn_cast(VD->getType().getNonReferenceType())) AVAttr = TTy->getDecl()->getAttr(); } else { // Assumptions for function parameters are emitted at the start of the // function, so there is no need to repeat that here. if (isa(VD)) return; AVAttr = VD->getAttr(); } } if (!AVAttr) if (const auto *TTy = dyn_cast(E->getType())) AVAttr = TTy->getDecl()->getAttr(); if (!AVAttr) return; Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment()); llvm::ConstantInt *AlignmentCI = cast(AlignmentValue); CGF.EmitAlignmentAssumption(V, AlignmentCI->getZExtValue()); } /// EmitLoadOfLValue - Given an expression with complex type that represents a /// value l-value, this method emits the address of the l-value, then loads /// and returns the result. Value *EmitLoadOfLValue(const Expr *E) { Value *V = EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load), E->getExprLoc()); EmitLValueAlignmentAssumption(E, V); return V; } /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *EmitConversionToBool(Value *Src, QualType DstTy); /// \brief Emit a check that a conversion to or from a floating-point type /// does not overflow. void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType, Value *Src, QualType SrcType, QualType DstType, llvm::Type *DstTy); /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy); /// EmitComplexToScalarConversion - Emit a conversion from the specified /// complex type to the specified destination type, where the destination type /// is an LLVM scalar type. Value *EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy); /// EmitNullValue - Emit a value that corresponds to null for the given type. Value *EmitNullValue(QualType Ty); /// EmitFloatToBoolConversion - Perform an FP to boolean conversion. Value *EmitFloatToBoolConversion(Value *V) { // Compare against 0.0 for fp scalars. llvm::Value *Zero = llvm::Constant::getNullValue(V->getType()); return Builder.CreateFCmpUNE(V, Zero, "tobool"); } /// EmitPointerToBoolConversion - Perform a pointer to boolean conversion. Value *EmitPointerToBoolConversion(Value *V) { Value *Zero = llvm::ConstantPointerNull::get( cast(V->getType())); return Builder.CreateICmpNE(V, Zero, "tobool"); } Value *EmitIntToBoolConversion(Value *V) { // Because of the type rules of C, we often end up computing a // logical value, then zero extending it to int, then wanting it // as a logical value again. Optimize this common case. if (llvm::ZExtInst *ZI = dyn_cast(V)) { if (ZI->getOperand(0)->getType() == Builder.getInt1Ty()) { Value *Result = ZI->getOperand(0); // If there aren't any more uses, zap the instruction to save space. // Note that there can be more uses, for example if this // is the result of an assignment. if (ZI->use_empty()) ZI->eraseFromParent(); return Result; } } return Builder.CreateIsNotNull(V, "tobool"); } //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// Value *Visit(Expr *E) { ApplyDebugLocation DL(CGF, E->getLocStart()); return StmtVisitor::Visit(E); } Value *VisitStmt(Stmt *S) { S->dump(CGF.getContext().getSourceManager()); llvm_unreachable("Stmt can't have complex result type!"); } Value *VisitExpr(Expr *S); Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } Value *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) { return Visit(E->getReplacement()); } Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) { return Visit(GE->getResultExpr()); } // Leaves. Value *VisitIntegerLiteral(const IntegerLiteral *E) { return Builder.getInt(E->getValue()); } Value *VisitFloatingLiteral(const FloatingLiteral *E) { return llvm::ConstantFP::get(VMContext, E->getValue()); } Value *VisitCharacterLiteral(const CharacterLiteral *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } Value *VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } Value *VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } Value *VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { return EmitNullValue(E->getType()); } Value *VisitGNUNullExpr(const GNUNullExpr *E) { return EmitNullValue(E->getType()); } Value *VisitOffsetOfExpr(OffsetOfExpr *E); Value *VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); return Builder.CreateBitCast(V, ConvertType(E->getType())); } Value *VisitSizeOfPackExpr(SizeOfPackExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength()); } Value *VisitPseudoObjectExpr(PseudoObjectExpr *E) { return CGF.EmitPseudoObjectRValue(E).getScalarVal(); } Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) { if (E->isGLValue()) return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E), E->getExprLoc()); // Otherwise, assume the mapping is the scalar directly. return CGF.getOpaqueRValueMapping(E).getScalarVal(); } // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { if (CodeGenFunction::ConstantEmission result = CGF.tryEmitAsConstant(E)) { if (result.isReference()) return EmitLoadOfLValue(result.getReferenceLValue(CGF, E), E->getExprLoc()); return result.getValue(); } return EmitLoadOfLValue(E); } Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) { return CGF.EmitObjCSelectorExpr(E); } Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E) { return CGF.EmitObjCProtocolExpr(E); } Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E); } Value *VisitObjCMessageExpr(ObjCMessageExpr *E) { if (E->getMethodDecl() && E->getMethodDecl()->getReturnType()->isReferenceType()) return EmitLoadOfLValue(E); return CGF.EmitObjCMessageExpr(E).getScalarVal(); } Value *VisitObjCIsaExpr(ObjCIsaExpr *E) { LValue LV = CGF.EmitObjCIsaExpr(E); Value *V = CGF.EmitLoadOfLValue(LV, E->getExprLoc()).getScalarVal(); return V; } Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitConvertVectorExpr(ConvertVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); } Value *VisitInitListExpr(InitListExpr *E); Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return EmitNullValue(E->getType()); } Value *VisitExplicitCastExpr(ExplicitCastExpr *E) { if (E->getType()->isVariablyModifiedType()) CGF.EmitVariablyModifiedType(E->getType()); if (CGDebugInfo *DI = CGF.getDebugInfo()) DI->EmitExplicitCastType(E->getType()); return VisitCastExpr(E); } Value *VisitCastExpr(CastExpr *E); Value *VisitCallExpr(const CallExpr *E) { if (E->getCallReturnType()->isReferenceType()) return EmitLoadOfLValue(E); Value *V = CGF.EmitCallExpr(E).getScalarVal(); EmitLValueAlignmentAssumption(E, V); return V; } Value *VisitStmtExpr(const StmtExpr *E); // Unary Operators. Value *VisitUnaryPostDec(const UnaryOperator *E) { LValue LV = EmitLValue(E->getSubExpr()); return EmitScalarPrePostIncDec(E, LV, false, false); } Value *VisitUnaryPostInc(const UnaryOperator *E) { LValue LV = EmitLValue(E->getSubExpr()); return EmitScalarPrePostIncDec(E, LV, true, false); } Value *VisitUnaryPreDec(const UnaryOperator *E) { LValue LV = EmitLValue(E->getSubExpr()); return EmitScalarPrePostIncDec(E, LV, false, true); } Value *VisitUnaryPreInc(const UnaryOperator *E) { LValue LV = EmitLValue(E->getSubExpr()); return EmitScalarPrePostIncDec(E, LV, true, true); } llvm::Value *EmitAddConsiderOverflowBehavior(const UnaryOperator *E, llvm::Value *InVal, llvm::Value *NextVal, bool IsInc); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); Value *VisitUnaryAddrOf(const UnaryOperator *E) { if (isa(E->getType())) // never sugared return CGF.CGM.getMemberPointerConstant(E); return EmitLValue(E->getSubExpr()).getAddress(); } Value *VisitUnaryDeref(const UnaryOperator *E) { if (E->getType()->isVoidType()) return Visit(E->getSubExpr()); // the actual value should be unused return EmitLoadOfLValue(E); } Value *VisitUnaryPlus(const UnaryOperator *E) { // This differs from gcc, though, most likely due to a bug in gcc. TestAndClearIgnoreResultAssign(); return Visit(E->getSubExpr()); } Value *VisitUnaryMinus (const UnaryOperator *E); Value *VisitUnaryNot (const UnaryOperator *E); Value *VisitUnaryLNot (const UnaryOperator *E); Value *VisitUnaryReal (const UnaryOperator *E); Value *VisitUnaryImag (const UnaryOperator *E); Value *VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } // C++ Value *VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E) { return EmitLoadOfLValue(E); } Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); return Visit(DIE->getExpr()); } Value *VisitCXXThisExpr(CXXThisExpr *TE) { return CGF.LoadCXXThis(); } Value *VisitExprWithCleanups(ExprWithCleanups *E) { CGF.enterFullExpression(E); CodeGenFunction::RunCleanupsScope Scope(CGF); return Visit(E->getSubExpr()); } Value *VisitCXXNewExpr(const CXXNewExpr *E) { return CGF.EmitCXXNewExpr(E); } Value *VisitCXXDeleteExpr(const CXXDeleteExpr *E) { CGF.EmitCXXDeleteExpr(E); return nullptr; } Value *VisitTypeTraitExpr(const TypeTraitExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue()); } Value *VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue()); } Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { // C++ [expr.pseudo]p1: // The result shall only be used as the operand for the function call // operator (), and the result of such a call has type void. The only // effect is the evaluation of the postfix-expression before the dot or // arrow. CGF.EmitScalarExpr(E->getBase()); return nullptr; } Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { return EmitNullValue(E->getType()); } Value *VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); return nullptr; } Value *VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { return Builder.getInt1(E->getValue()); } // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (Ops.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(Ops); } } if (Ops.Ty->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) return EmitOverflowCheckedBinOp(Ops); if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } /// Create a binary op that checks for overflow. /// Currently only supports +, - and *. Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops); // Check for undefined division and modulus behaviors. void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops, llvm::Value *Zero,bool isDiv); // Common helper for getting how wide LHS of shift is. static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS); Value *EmitDiv(const BinOpInfo &Ops); Value *EmitRem(const BinOpInfo &Ops); Value *EmitAdd(const BinOpInfo &Ops); Value *EmitSub(const BinOpInfo &Ops); Value *EmitShl(const BinOpInfo &Ops); Value *EmitShr(const BinOpInfo &Ops); Value *EmitAnd(const BinOpInfo &Ops) { return Builder.CreateAnd(Ops.LHS, Ops.RHS, "and"); } Value *EmitXor(const BinOpInfo &Ops) { return Builder.CreateXor(Ops.LHS, Ops.RHS, "xor"); } Value *EmitOr (const BinOpInfo &Ops) { return Builder.CreateOr(Ops.LHS, Ops.RHS, "or"); } BinOpInfo EmitBinOps(const BinaryOperator *E); LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*F)(const BinOpInfo &), Value *&Result); Value *EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); // Binary operators and binary compound assignment operators. #define HANDLEBINOP(OP) \ Value *VisitBin ## OP(const BinaryOperator *E) { \ return Emit ## OP(EmitBinOps(E)); \ } \ Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \ return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \ } HANDLEBINOP(Mul) HANDLEBINOP(Div) HANDLEBINOP(Rem) HANDLEBINOP(Add) HANDLEBINOP(Sub) HANDLEBINOP(Shl) HANDLEBINOP(Shr) HANDLEBINOP(And) HANDLEBINOP(Xor) HANDLEBINOP(Or) #undef HANDLEBINOP // Comparisons. Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc, unsigned SICmpOpc, unsigned FCmpOpc); #define VISITCOMP(CODE, UI, SI, FP) \ Value *VisitBin##CODE(const BinaryOperator *E) { \ return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \ llvm::FCmpInst::FP); } VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT) VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT) VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE) VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE) VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ) VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE) #undef VISITCOMP Value *VisitBinAssign (const BinaryOperator *E); Value *VisitBinLAnd (const BinaryOperator *E); Value *VisitBinLOr (const BinaryOperator *E); Value *VisitBinComma (const BinaryOperator *E); Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); } Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); } // Other Operators. Value *VisitBlockExpr(const BlockExpr *BE); Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *); Value *VisitChooseExpr(ChooseExpr *CE); Value *VisitVAArgExpr(VAArgExpr *VE); Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } Value *VisitObjCBoxedExpr(ObjCBoxedExpr *E) { return CGF.EmitObjCBoxedExpr(E); } Value *VisitObjCArrayLiteral(ObjCArrayLiteral *E) { return CGF.EmitObjCArrayLiteral(E); } Value *VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { return CGF.EmitObjCDictionaryLiteral(E); } Value *VisitAsTypeExpr(AsTypeExpr *CE); Value *VisitAtomicExpr(AtomicExpr *AE); }; } // end anonymous namespace. //===----------------------------------------------------------------------===// // Utilities //===----------------------------------------------------------------------===// /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { assert(SrcType.isCanonical() && "EmitScalarConversion strips typedefs"); if (SrcType->isRealFloatingType()) return EmitFloatToBoolConversion(Src); if (const MemberPointerType *MPT = dyn_cast(SrcType)) return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT); assert((SrcType->isIntegerType() || isa(Src->getType())) && "Unknown scalar type to convert"); if (isa(Src->getType())) return EmitIntToBoolConversion(Src); assert(isa(Src->getType())); return EmitPointerToBoolConversion(Src); } void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType, Value *Src, QualType SrcType, QualType DstType, llvm::Type *DstTy) { CodeGenFunction::SanitizerScope SanScope(&CGF); using llvm::APFloat; using llvm::APSInt; llvm::Type *SrcTy = Src->getType(); llvm::Value *Check = nullptr; if (llvm::IntegerType *IntTy = dyn_cast(SrcTy)) { // Integer to floating-point. This can fail for unsigned short -> __half // or unsigned __int128 -> float. assert(DstType->isFloatingType()); bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType(); APFloat LargestFloat = APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType)); APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned); bool IsExact; if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero, &IsExact) != APFloat::opOK) // The range of representable values of this floating point type includes // all values of this integer type. Don't need an overflow check. return; llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt); if (SrcIsUnsigned) Check = Builder.CreateICmpULE(Src, Max); else { llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt); llvm::Value *GE = Builder.CreateICmpSGE(Src, Min); llvm::Value *LE = Builder.CreateICmpSLE(Src, Max); Check = Builder.CreateAnd(GE, LE); } } else { const llvm::fltSemantics &SrcSema = CGF.getContext().getFloatTypeSemantics(OrigSrcType); if (isa(DstTy)) { // Floating-point to integer. This has undefined behavior if the source is // +-Inf, NaN, or doesn't fit into the destination type (after truncation // to an integer). unsigned Width = CGF.getContext().getIntWidth(DstType); bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType(); APSInt Min = APSInt::getMinValue(Width, Unsigned); APFloat MinSrc(SrcSema, APFloat::uninitialized); if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) & APFloat::opOverflow) // Don't need an overflow check for lower bound. Just check for // -Inf/NaN. MinSrc = APFloat::getInf(SrcSema, true); else // Find the largest value which is too small to represent (before // truncation toward zero). MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative); APSInt Max = APSInt::getMaxValue(Width, Unsigned); APFloat MaxSrc(SrcSema, APFloat::uninitialized); if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) & APFloat::opOverflow) // Don't need an overflow check for upper bound. Just check for // +Inf/NaN. MaxSrc = APFloat::getInf(SrcSema, false); else // Find the smallest value which is too large to represent (before // truncation toward zero). MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive); // If we're converting from __half, convert the range to float to match // the type of src. if (OrigSrcType->isHalfType()) { const llvm::fltSemantics &Sema = CGF.getContext().getFloatTypeSemantics(SrcType); bool IsInexact; MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); } llvm::Value *GE = Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc)); llvm::Value *LE = Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); Check = Builder.CreateAnd(GE, LE); } else { // FIXME: Maybe split this sanitizer out from float-cast-overflow. // // Floating-point to floating-point. This has undefined behavior if the // source is not in the range of representable values of the destination // type. The C and C++ standards are spectacularly unclear here. We // diagnose finite out-of-range conversions, but allow infinities and NaNs // to convert to the corresponding value in the smaller type. // // C11 Annex F gives all such conversions defined behavior for IEC 60559 // conforming implementations. Unfortunately, LLVM's fptrunc instruction // does not. // Converting from a lower rank to a higher rank can never have // undefined behavior, since higher-rank types must have a superset // of values of lower-rank types. if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1) return; assert(!OrigSrcType->isHalfType() && "should not check conversion from __half, it has the lowest rank"); const llvm::fltSemantics &DstSema = CGF.getContext().getFloatTypeSemantics(DstType); APFloat MinBad = APFloat::getLargest(DstSema, false); APFloat MaxBad = APFloat::getInf(DstSema, false); bool IsInexact; MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact); MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact); Value *AbsSrc = CGF.EmitNounwindRuntimeCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src); llvm::Value *GE = Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad)); llvm::Value *LE = Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad)); Check = Builder.CreateNot(Builder.CreateAnd(GE, LE)); } } // FIXME: Provide a SourceLocation. llvm::Constant *StaticArgs[] = { CGF.EmitCheckTypeDescriptor(OrigSrcType), CGF.EmitCheckTypeDescriptor(DstType) }; CGF.EmitCheck(std::make_pair(Check, SanitizerKind::FloatCastOverflow), "float_cast_overflow", StaticArgs, OrigSrc); } /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, QualType DstType) { SrcType = CGF.getContext().getCanonicalType(SrcType); DstType = CGF.getContext().getCanonicalType(DstType); if (SrcType == DstType) return Src; if (DstType->isVoidType()) return nullptr; llvm::Value *OrigSrc = Src; QualType OrigSrcType = SrcType; llvm::Type *SrcTy = Src->getType(); // If casting to/from storage-only half FP, use special intrinsics. if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType && !CGF.getContext().getLangOpts().HalfArgsAndReturns) { Src = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, CGF.CGM.FloatTy), Src); SrcType = CGF.getContext().FloatTy; SrcTy = CGF.FloatTy; } // Handle conversions to bool first, they are special: comparisons against 0. if (DstType->isBooleanType()) return EmitConversionToBool(Src, SrcType); llvm::Type *DstTy = ConvertType(DstType); // Ignore conversions like int -> uint. if (SrcTy == DstTy) return Src; // Handle pointer conversions next: pointers can only be converted to/from // other pointers and integers. Check for pointer types in terms of LLVM, as // some native types (like Obj-C id) may map to a pointer type. if (isa(DstTy)) { // The source value may be an integer, or a pointer. if (isa(SrcTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); // First, convert to the correct width so that we control the kind of // extension. llvm::Type *MiddleTy = CGF.IntPtrTy; bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); // Then, cast to pointer. return Builder.CreateIntToPtr(IntResult, DstTy, "conv"); } if (isa(SrcTy)) { // Must be an ptr to int cast. assert(isa(DstTy) && "not ptr->int?"); return Builder.CreatePtrToInt(Src, DstTy, "conv"); } // A scalar can be splatted to an extended vector of the same element type if (DstType->isExtVectorType() && !SrcType->isVectorType()) { // Cast the scalar to element type QualType EltTy = DstType->getAs()->getElementType(); llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy); // Splat the element across to all elements unsigned NumElements = cast(DstTy)->getNumElements(); return Builder.CreateVectorSplat(NumElements, Elt, "splat"); } // Allow bitcast from vector to integer/fp of the same size. if (isa(SrcTy) || isa(DstTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); // Finally, we have the arithmetic types: real int/float. Value *Res = nullptr; llvm::Type *ResTy = DstTy; // An overflowing conversion has undefined behavior if either the source type // or the destination type is a floating-point type. if (CGF.SanOpts.has(SanitizerKind::FloatCastOverflow) && (OrigSrcType->isFloatingType() || DstType->isFloatingType())) EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy); // Cast to half via float if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType && !CGF.getContext().getLangOpts().HalfArgsAndReturns) DstTy = CGF.FloatTy; if (isa(SrcTy)) { bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); if (isa(DstTy)) Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); else if (InputSigned) Res = Builder.CreateSIToFP(Src, DstTy, "conv"); else Res = Builder.CreateUIToFP(Src, DstTy, "conv"); } else if (isa(DstTy)) { assert(SrcTy->isFloatingPointTy() && "Unknown real conversion"); if (DstType->isSignedIntegerOrEnumerationType()) Res = Builder.CreateFPToSI(Src, DstTy, "conv"); else Res = Builder.CreateFPToUI(Src, DstTy, "conv"); } else { assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() && "Unknown real conversion"); if (DstTy->getTypeID() < SrcTy->getTypeID()) Res = Builder.CreateFPTrunc(Src, DstTy, "conv"); else Res = Builder.CreateFPExt(Src, DstTy, "conv"); } if (DstTy != ResTy) { assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion"); Res = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy), Res); } return Res; } /// EmitComplexToScalarConversion - Emit a conversion from the specified complex /// type to the specified destination type, where the destination type is an /// LLVM scalar type. Value *ScalarExprEmitter:: EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, QualType SrcTy, QualType DstTy) { // Get the source element type. SrcTy = SrcTy->castAs()->getElementType(); // Handle conversions to bool first, they are special: comparisons against 0. if (DstTy->isBooleanType()) { // Complex != 0 -> (Real != 0) | (Imag != 0) Src.first = EmitScalarConversion(Src.first, SrcTy, DstTy); Src.second = EmitScalarConversion(Src.second, SrcTy, DstTy); return Builder.CreateOr(Src.first, Src.second, "tobool"); } // C99 6.3.1.7p2: "When a value of complex type is converted to a real type, // the imaginary part of the complex value is discarded and the value of the // real part is converted according to the conversion rules for the // corresponding real type. return EmitScalarConversion(Src.first, SrcTy, DstTy); } Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { return CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(Ty), Ty); } /// \brief Emit a sanitization check for the given "binary" operation (which /// might actually be a unary increment which has been lowered to a binary /// operation). The check passes if all values in \p Checks (which are \c i1), /// are \c true. void ScalarExprEmitter::EmitBinOpCheck( ArrayRef> Checks, const BinOpInfo &Info) { assert(CGF.IsSanitizerScope); StringRef CheckName; SmallVector StaticData; SmallVector DynamicData; BinaryOperatorKind Opcode = Info.Opcode; if (BinaryOperator::isCompoundAssignmentOp(Opcode)) Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode); StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc())); const UnaryOperator *UO = dyn_cast(Info.E); if (UO && UO->getOpcode() == UO_Minus) { CheckName = "negate_overflow"; StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType())); DynamicData.push_back(Info.RHS); } else { if (BinaryOperator::isShiftOp(Opcode)) { // Shift LHS negative or too large, or RHS out of bounds. CheckName = "shift_out_of_bounds"; const BinaryOperator *BO = cast(Info.E); StaticData.push_back( CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType())); StaticData.push_back( CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType())); } else if (Opcode == BO_Div || Opcode == BO_Rem) { // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1). CheckName = "divrem_overflow"; StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty)); } else { // Arithmetic overflow (+, -, *). switch (Opcode) { case BO_Add: CheckName = "add_overflow"; break; case BO_Sub: CheckName = "sub_overflow"; break; case BO_Mul: CheckName = "mul_overflow"; break; default: llvm_unreachable("unexpected opcode for bin op check"); } StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty)); } DynamicData.push_back(Info.LHS); DynamicData.push_back(Info.RHS); } CGF.EmitCheck(Checks, CheckName, StaticData, DynamicData); } //===----------------------------------------------------------------------===// // Visitor Methods //===----------------------------------------------------------------------===// Value *ScalarExprEmitter::VisitExpr(Expr *E) { CGF.ErrorUnsupported(E, "scalar expression"); if (E->getType()->isVoidType()) return nullptr; return llvm::UndefValue::get(CGF.ConvertType(E->getType())); } Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { // Vector Mask Case if (E->getNumSubExprs() == 2 || (E->getNumSubExprs() == 3 && E->getExpr(2)->getType()->isVectorType())) { Value *LHS = CGF.EmitScalarExpr(E->getExpr(0)); Value *RHS = CGF.EmitScalarExpr(E->getExpr(1)); Value *Mask; llvm::VectorType *LTy = cast(LHS->getType()); unsigned LHSElts = LTy->getNumElements(); if (E->getNumSubExprs() == 3) { Mask = CGF.EmitScalarExpr(E->getExpr(2)); // Shuffle LHS & RHS into one input vector. SmallVector concat; for (unsigned i = 0; i != LHSElts; ++i) { concat.push_back(Builder.getInt32(2*i)); concat.push_back(Builder.getInt32(2*i+1)); } Value* CV = llvm::ConstantVector::get(concat); LHS = Builder.CreateShuffleVector(LHS, RHS, CV, "concat"); LHSElts *= 2; } else { Mask = RHS; } llvm::VectorType *MTy = cast(Mask->getType()); llvm::Constant* EltMask; EltMask = llvm::ConstantInt::get(MTy->getElementType(), llvm::NextPowerOf2(LHSElts-1)-1); // Mask off the high bits of each shuffle index. Value *MaskBits = llvm::ConstantVector::getSplat(MTy->getNumElements(), EltMask); Mask = Builder.CreateAnd(Mask, MaskBits, "mask"); // newv = undef // mask = mask & maskbits // for each elt // n = extract mask i // x = extract val n // newv = insert newv, x, i llvm::VectorType *RTy = llvm::VectorType::get(LTy->getElementType(), MTy->getNumElements()); Value* NewV = llvm::UndefValue::get(RTy); for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) { Value *IIndx = llvm::ConstantInt::get(CGF.SizeTy, i); Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx"); Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt"); NewV = Builder.CreateInsertElement(NewV, VExt, IIndx, "shuf_ins"); } return NewV; } Value* V1 = CGF.EmitScalarExpr(E->getExpr(0)); Value* V2 = CGF.EmitScalarExpr(E->getExpr(1)); SmallVector indices; for (unsigned i = 2; i < E->getNumSubExprs(); ++i) { llvm::APSInt Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2); // Check for -1 and output it as undef in the IR. if (Idx.isSigned() && Idx.isAllOnesValue()) indices.push_back(llvm::UndefValue::get(CGF.Int32Ty)); else indices.push_back(Builder.getInt32(Idx.getZExtValue())); } Value *SV = llvm::ConstantVector::get(indices); return Builder.CreateShuffleVector(V1, V2, SV, "shuffle"); } Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) { QualType SrcType = E->getSrcExpr()->getType(), DstType = E->getType(); Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); SrcType = CGF.getContext().getCanonicalType(SrcType); DstType = CGF.getContext().getCanonicalType(DstType); if (SrcType == DstType) return Src; assert(SrcType->isVectorType() && "ConvertVector source type must be a vector"); assert(DstType->isVectorType() && "ConvertVector destination type must be a vector"); llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = ConvertType(DstType); // Ignore conversions like int -> uint. if (SrcTy == DstTy) return Src; QualType SrcEltType = SrcType->getAs()->getElementType(), DstEltType = DstType->getAs()->getElementType(); assert(SrcTy->isVectorTy() && "ConvertVector source IR type must be a vector"); assert(DstTy->isVectorTy() && "ConvertVector destination IR type must be a vector"); llvm::Type *SrcEltTy = SrcTy->getVectorElementType(), *DstEltTy = DstTy->getVectorElementType(); if (DstEltType->isBooleanType()) { assert((SrcEltTy->isFloatingPointTy() || isa(SrcEltTy)) && "Unknown boolean conversion"); llvm::Value *Zero = llvm::Constant::getNullValue(SrcTy); if (SrcEltTy->isFloatingPointTy()) { return Builder.CreateFCmpUNE(Src, Zero, "tobool"); } else { return Builder.CreateICmpNE(Src, Zero, "tobool"); } } // We have the arithmetic types: real int/float. Value *Res = nullptr; if (isa(SrcEltTy)) { bool InputSigned = SrcEltType->isSignedIntegerOrEnumerationType(); if (isa(DstEltTy)) Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); else if (InputSigned) Res = Builder.CreateSIToFP(Src, DstTy, "conv"); else Res = Builder.CreateUIToFP(Src, DstTy, "conv"); } else if (isa(DstEltTy)) { assert(SrcEltTy->isFloatingPointTy() && "Unknown real conversion"); if (DstEltType->isSignedIntegerOrEnumerationType()) Res = Builder.CreateFPToSI(Src, DstTy, "conv"); else Res = Builder.CreateFPToUI(Src, DstTy, "conv"); } else { assert(SrcEltTy->isFloatingPointTy() && DstEltTy->isFloatingPointTy() && "Unknown real conversion"); if (DstEltTy->getTypeID() < SrcEltTy->getTypeID()) Res = Builder.CreateFPTrunc(Src, DstTy, "conv"); else Res = Builder.CreateFPExt(Src, DstTy, "conv"); } return Res; } Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { llvm::APSInt Value; if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { if (E->isArrow()) CGF.EmitScalarExpr(E->getBase()); else EmitLValue(E->getBase()); return Builder.getInt(Value); } return EmitLoadOfLValue(E); } Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { TestAndClearIgnoreResultAssign(); // Emit subscript expressions in rvalue context's. For most cases, this just // loads the lvalue formed by the subscript expr. However, we have to be // careful, because the base of a vector subscript is occasionally an rvalue, // so we can't get it as an lvalue. if (!E->getBase()->getType()->isVectorType()) return EmitLoadOfLValue(E); // Handle the vector case. The base must be a vector, the index must be an // integer value. Value *Base = Visit(E->getBase()); Value *Idx = Visit(E->getIdx()); QualType IdxTy = E->getIdx()->getType(); if (CGF.SanOpts.has(SanitizerKind::ArrayBounds)) CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true); return Builder.CreateExtractElement(Base, Idx, "vecext"); } static llvm::Constant *getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, unsigned Off, llvm::Type *I32Ty) { int MV = SVI->getMaskValue(Idx); if (MV == -1) return llvm::UndefValue::get(I32Ty); return llvm::ConstantInt::get(I32Ty, Off+MV); } Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { bool Ignore = TestAndClearIgnoreResultAssign(); (void)Ignore; assert (Ignore == false && "init list ignored"); unsigned NumInitElements = E->getNumInits(); if (E->hadArrayRangeDesignator()) CGF.ErrorUnsupported(E, "GNU array range designator extension"); llvm::VectorType *VType = dyn_cast(ConvertType(E->getType())); if (!VType) { if (NumInitElements == 0) { // C++11 value-initialization for the scalar. return EmitNullValue(E->getType()); } // We have a scalar in braces. Just use the first element. return Visit(E->getInit(0)); } unsigned ResElts = VType->getNumElements(); // Loop over initializers collecting the Value for each, and remembering // whether the source was swizzle (ExtVectorElementExpr). This will allow // us to fold the shuffle for the swizzle into the shuffle for the vector // initializer, since LLVM optimizers generally do not want to touch // shuffles. unsigned CurIdx = 0; bool VIsUndefShuffle = false; llvm::Value *V = llvm::UndefValue::get(VType); for (unsigned i = 0; i != NumInitElements; ++i) { Expr *IE = E->getInit(i); Value *Init = Visit(IE); SmallVector Args; llvm::VectorType *VVT = dyn_cast(Init->getType()); // Handle scalar elements. If the scalar initializer is actually one // element of a different vector of the same width, use shuffle instead of // extract+insert. if (!VVT) { if (isa(IE)) { llvm::ExtractElementInst *EI = cast(Init); if (EI->getVectorOperandType()->getNumElements() == ResElts) { llvm::ConstantInt *C = cast(EI->getIndexOperand()); Value *LHS = nullptr, *RHS = nullptr; if (CurIdx == 0) { // insert into undef -> shuffle (src, undef) Args.push_back(C); Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty)); LHS = EI->getVectorOperand(); RHS = V; VIsUndefShuffle = true; } else if (VIsUndefShuffle) { // insert into undefshuffle && size match -> shuffle (v, src) llvm::ShuffleVectorInst *SVV = cast(V); for (unsigned j = 0; j != CurIdx; ++j) Args.push_back(getMaskElt(SVV, j, 0, CGF.Int32Ty)); Args.push_back(Builder.getInt32(ResElts + C->getZExtValue())); Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty)); LHS = cast(V)->getOperand(0); RHS = EI->getVectorOperand(); VIsUndefShuffle = false; } if (!Args.empty()) { llvm::Constant *Mask = llvm::ConstantVector::get(Args); V = Builder.CreateShuffleVector(LHS, RHS, Mask); ++CurIdx; continue; } } } V = Builder.CreateInsertElement(V, Init, Builder.getInt32(CurIdx), "vecinit"); VIsUndefShuffle = false; ++CurIdx; continue; } unsigned InitElts = VVT->getNumElements(); // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's // input is the same width as the vector being constructed, generate an // optimized shuffle of the swizzle input into the result. unsigned Offset = (CurIdx == 0) ? 0 : ResElts; if (isa(IE)) { llvm::ShuffleVectorInst *SVI = cast(Init); Value *SVOp = SVI->getOperand(0); llvm::VectorType *OpTy = cast(SVOp->getType()); if (OpTy->getNumElements() == ResElts) { for (unsigned j = 0; j != CurIdx; ++j) { // If the current vector initializer is a shuffle with undef, merge // this shuffle directly into it. if (VIsUndefShuffle) { Args.push_back(getMaskElt(cast(V), j, 0, CGF.Int32Ty)); } else { Args.push_back(Builder.getInt32(j)); } } for (unsigned j = 0, je = InitElts; j != je; ++j) Args.push_back(getMaskElt(SVI, j, Offset, CGF.Int32Ty)); Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty)); if (VIsUndefShuffle) V = cast(V)->getOperand(0); Init = SVOp; } } // Extend init to result vector length, and then shuffle its contribution // to the vector initializer into V. if (Args.empty()) { for (unsigned j = 0; j != InitElts; ++j) Args.push_back(Builder.getInt32(j)); Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty)); llvm::Constant *Mask = llvm::ConstantVector::get(Args); Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT), Mask, "vext"); Args.clear(); for (unsigned j = 0; j != CurIdx; ++j) Args.push_back(Builder.getInt32(j)); for (unsigned j = 0; j != InitElts; ++j) Args.push_back(Builder.getInt32(j+Offset)); Args.resize(ResElts, llvm::UndefValue::get(CGF.Int32Ty)); } // If V is undef, make sure it ends up on the RHS of the shuffle to aid // merging subsequent shuffles into this one. if (CurIdx == 0) std::swap(V, Init); llvm::Constant *Mask = llvm::ConstantVector::get(Args); V = Builder.CreateShuffleVector(V, Init, Mask, "vecinit"); VIsUndefShuffle = isa(Init); CurIdx += InitElts; } // FIXME: evaluate codegen vs. shuffling against constant null vector. // Emit remaining default initializers. llvm::Type *EltTy = VType->getElementType(); // Emit remaining default initializers for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) { Value *Idx = Builder.getInt32(CurIdx); llvm::Value *Init = llvm::Constant::getNullValue(EltTy); V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); } return V; } static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { const Expr *E = CE->getSubExpr(); if (CE->getCastKind() == CK_UncheckedDerivedToBase) return false; if (isa(E)) { // We always assume that 'this' is never null. return false; } if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { // And that glvalue casts are never null. if (ICE->getValueKind() != VK_RValue) return false; } return true; } // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { Expr *E = CE->getSubExpr(); QualType DestTy = CE->getType(); CastKind Kind = CE->getCastKind(); if (!DestTy->isVoidType()) TestAndClearIgnoreResultAssign(); // Since almost all cast kinds apply to scalars, this switch doesn't have // a default case, so the compiler will warn on a missing case. The cases // are in the same order as in the CastKind enum. switch (Kind) { case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); case CK_BuiltinFnToFnPtr: llvm_unreachable("builtin functions are handled elsewhere"); case CK_LValueBitCast: case CK_ObjCObjectLValueCast: { Value *V = EmitLValue(E).getAddress(); V = Builder.CreateBitCast(V, ConvertType(CGF.getContext().getPointerType(DestTy))); return EmitLoadOfLValue(CGF.MakeNaturalAlignAddrLValue(V, DestTy), CE->getExprLoc()); } case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: { Value *Src = Visit(const_cast(E)); llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = ConvertType(DestTy); if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() && SrcTy->getPointerAddressSpace() != DstTy->getPointerAddressSpace()) { llvm_unreachable("wrong cast for pointers in different address spaces" "(must be an address space cast)!"); } return Builder.CreateBitCast(Src, DstTy); } case CK_AddressSpaceConversion: { Value *Src = Visit(const_cast(E)); return Builder.CreateAddrSpaceCast(Src, ConvertType(DestTy)); } case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_NoOp: case CK_UserDefinedConversion: return Visit(const_cast(E)); case CK_BaseToDerived: { const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl(); assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!"); llvm::Value *V = Visit(E); llvm::Value *Derived = CGF.GetAddressOfDerivedClass(V, DerivedClassDecl, CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE)); // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is // performed and the object is not of the derived type. if (CGF.sanitizePerformTypeCheck()) CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(), Derived, DestTy->getPointeeType()); return Derived; } case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { const CXXRecordDecl *DerivedClassDecl = E->getType()->getPointeeCXXRecordDecl(); assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!"); return CGF.GetAddressOfBaseClass( Visit(E), DerivedClassDecl, CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE), CE->getExprLoc()); } case CK_Dynamic: { Value *V = Visit(const_cast(E)); const CXXDynamicCastExpr *DCE = cast(CE); return CGF.EmitDynamicCast(V, DCE); } case CK_ArrayToPointerDecay: { assert(E->getType()->isArrayType() && "Array to pointer decay must have array source type!"); Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays. // Note that VLA pointers are always decayed, so we don't need to do // anything here. if (!E->getType()->isVariableArrayType()) { assert(isa(V->getType()) && "Expected pointer"); V = CGF.Builder.CreatePointerCast( V, ConvertType(E->getType())->getPointerTo( V->getType()->getPointerAddressSpace())); assert(isa(V->getType()->getPointerElementType()) && "Expected pointer to array"); V = Builder.CreateStructGEP(V, 0, "arraydecay"); } // Make sure the array decay ends up being the right type. This matters if // the array type was of an incomplete type. return CGF.Builder.CreatePointerCast(V, ConvertType(CE->getType())); } case CK_FunctionToPointerDecay: return EmitLValue(E).getAddress(); case CK_NullToPointer: if (MustVisitNullValue(E)) (void) Visit(E); return llvm::ConstantPointerNull::get( cast(ConvertType(DestTy))); case CK_NullToMemberPointer: { if (MustVisitNullValue(E)) (void) Visit(E); const MemberPointerType *MPT = CE->getType()->getAs(); return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); } case CK_ReinterpretMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: { Value *Src = Visit(E); // Note that the AST doesn't distinguish between checked and // unchecked member pointer conversions, so we always have to // implement checked conversions here. This is inefficient when // actual control flow may be required in order to perform the // check, which it is for data member pointers (but not member // function pointers on Itanium and ARM). return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src); } case CK_ARCProduceObject: return CGF.EmitARCRetainScalarExpr(E); case CK_ARCConsumeObject: return CGF.EmitObjCConsumeObject(E->getType(), Visit(E)); case CK_ARCReclaimReturnedObject: { llvm::Value *value = Visit(E); value = CGF.EmitARCRetainAutoreleasedReturnValue(value); return CGF.EmitObjCConsumeObject(E->getType(), value); } case CK_ARCExtendBlockObject: return CGF.EmitARCExtendBlockObject(E); case CK_CopyAndAutoreleaseBlockObject: return CGF.EmitBlockCopyAndAutorelease(Visit(E), E->getType()); case CK_FloatingRealToComplex: case CK_FloatingComplexCast: case CK_IntegralRealToComplex: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_FloatingComplexToIntegralComplex: case CK_ConstructorConversion: case CK_ToUnion: llvm_unreachable("scalar cast to non-scalar value"); case CK_LValueToRValue: assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy)); assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!"); return Visit(const_cast(E)); case CK_IntegralToPointer: { Value *Src = Visit(const_cast(E)); // First, convert to the correct width so that we control the kind of // extension. llvm::Type *MiddleTy = CGF.IntPtrTy; bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); } case CK_PointerToIntegral: assert(!DestTy->isBooleanType() && "bool should use PointerToBool"); return Builder.CreatePtrToInt(Visit(E), ConvertType(DestTy)); case CK_ToVoid: { CGF.EmitIgnoredExpr(E); return nullptr; } case CK_VectorSplat: { llvm::Type *DstTy = ConvertType(DestTy); Value *Elt = Visit(const_cast(E)); Elt = EmitScalarConversion(Elt, E->getType(), DestTy->getAs()->getElementType()); // Splat the element across to all elements unsigned NumElements = cast(DstTy)->getNumElements(); return Builder.CreateVectorSplat(NumElements, Elt, "splat"); } case CK_IntegralCast: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: return EmitPointerToBoolConversion(Visit(E)); case CK_FloatingToBoolean: return EmitFloatToBoolConversion(Visit(E)); case CK_MemberPointerToBoolean: { llvm::Value *MemPtr = Visit(E); const MemberPointerType *MPT = E->getType()->getAs(); return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT); } case CK_FloatingComplexToReal: case CK_IntegralComplexToReal: return CGF.EmitComplexExpr(E, false, true).first; case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: { CodeGenFunction::ComplexPairTy V = CGF.EmitComplexExpr(E); // TODO: kill this function off, inline appropriate case here return EmitComplexToScalarConversion(V, E->getType(), DestTy); } case CK_ZeroToOCLEvent: { assert(DestTy->isEventT() && "CK_ZeroToOCLEvent cast on non-event type"); return llvm::Constant::getNullValue(ConvertType(DestTy)); } } llvm_unreachable("unknown scalar cast"); } Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { CodeGenFunction::StmtExprEvaluation eval(CGF); llvm::Value *RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(), !E->getType()->isVoidType()); if (!RetAlloca) return nullptr; return CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(RetAlloca, E->getType()), E->getExprLoc()); } //===----------------------------------------------------------------------===// // Unary Operators //===----------------------------------------------------------------------===// llvm::Value *ScalarExprEmitter:: EmitAddConsiderOverflowBehavior(const UnaryOperator *E, llvm::Value *InVal, llvm::Value *NextVal, bool IsInc) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); // Fall through. case LangOptions::SOB_Trapping: BinOpInfo BinOp; BinOp.LHS = InVal; BinOp.RHS = NextVal; BinOp.Ty = E->getType(); BinOp.Opcode = BO_Add; BinOp.FPContractable = false; BinOp.E = E; return EmitOverflowCheckedBinOp(BinOp); } llvm_unreachable("Unknown SignedOverflowBehaviorTy"); } llvm::Value * ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { QualType type = E->getSubExpr()->getType(); llvm::PHINode *atomicPHI = nullptr; llvm::Value *value; llvm::Value *input; int amount = (isInc ? 1 : -1); if (const AtomicType *atomicTy = type->getAs()) { type = atomicTy->getValueType(); if (isInc && type->isBooleanType()) { llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type); if (isPre) { Builder.Insert(new llvm::StoreInst(True, LV.getAddress(), LV.isVolatileQualified(), LV.getAlignment().getQuantity(), llvm::SequentiallyConsistent)); return Builder.getTrue(); } // For atomic bool increment, we just store true and return it for // preincrement, do an atomic swap with true for postincrement return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, LV.getAddress(), True, llvm::SequentiallyConsistent); } // Special case for atomic increment / decrement on integers, emit // atomicrmw instructions. We skip this if we want to be doing overflow // checking, and fall into the slow path with the atomic cmpxchg loop. if (!type->isBooleanType() && type->isIntegerType() && !(type->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) && CGF.getLangOpts().getSignedOverflowBehavior() != LangOptions::SOB_Trapping) { llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add : llvm::AtomicRMWInst::Sub; llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add : llvm::Instruction::Sub; llvm::Value *amt = CGF.EmitToMemory( llvm::ConstantInt::get(ConvertType(type), 1, true), type); llvm::Value *old = Builder.CreateAtomicRMW(aop, LV.getAddress(), amt, llvm::SequentiallyConsistent); return isPre ? Builder.CreateBinOp(op, old, amt) : old; } value = EmitLoadOfLValue(LV, E->getExprLoc()); input = value; // For every other atomic operation, we need to emit a load-op-cmpxchg loop llvm::BasicBlock *startBB = Builder.GetInsertBlock(); llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn); value = CGF.EmitToMemory(value, type); Builder.CreateBr(opBB); Builder.SetInsertPoint(opBB); atomicPHI = Builder.CreatePHI(value->getType(), 2); atomicPHI->addIncoming(value, startBB); value = atomicPHI; } else { value = EmitLoadOfLValue(LV, E->getExprLoc()); input = value; } // Special case of integer increment that we have to check first: bool++. // Due to promotion rules, we get: // bool++ -> bool = bool + 1 // -> bool = (int)bool + 1 // -> bool = ((int)bool + 1 != 0) // An interesting aspect of this is that increment is always true. // Decrement does not have this property. if (isInc && type->isBooleanType()) { value = Builder.getTrue(); // Most common case by far: integer increment. } else if (type->isIntegerType()) { llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); // Note that signed integer inc/dec with width less than int can't // overflow because of promotion rules; we're just eliding a few steps here. bool CanOverflow = value->getType()->getIntegerBitWidth() >= CGF.IntTy->getIntegerBitWidth(); if (CanOverflow && type->isSignedIntegerOrEnumerationType()) { value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc); } else if (CanOverflow && type->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) { BinOpInfo BinOp; BinOp.LHS = value; BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false); BinOp.Ty = E->getType(); BinOp.Opcode = isInc ? BO_Add : BO_Sub; BinOp.FPContractable = false; BinOp.E = E; value = EmitOverflowCheckedBinOp(BinOp); } else value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); // Next most common: pointer increment. } else if (const PointerType *ptr = type->getAs()) { QualType type = ptr->getPointeeType(); // VLA types don't have constant size. if (const VariableArrayType *vla = CGF.getContext().getAsVariableArrayType(type)) { llvm::Value *numElts = CGF.getVLASize(vla).first; if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, numElts, "vla.inc"); else value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc"); // Arithmetic on function pointers (!) is just +-1. } else if (type->isFunctionType()) { llvm::Value *amt = Builder.getInt32(amount); value = CGF.EmitCastToVoidPtr(value); if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.funcptr"); else value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr"); value = Builder.CreateBitCast(value, input->getType()); // For everything else, we can just do a simple increment. } else { llvm::Value *amt = Builder.getInt32(amount); if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.ptr"); else value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr"); } // Vector increment/decrement. } else if (type->isVectorType()) { if (type->hasIntegerRepresentation()) { llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); } else { value = Builder.CreateFAdd( value, llvm::ConstantFP::get(value->getType(), amount), isInc ? "inc" : "dec"); } // Floating point. } else if (type->isRealFloatingType()) { // Add the inc/dec to the real part. llvm::Value *amt; if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType && !CGF.getContext().getLangOpts().HalfArgsAndReturns) { // Another special case: half FP increment should be done via float value = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16, CGF.CGM.FloatTy), input); } if (value->getType()->isFloatTy()) amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast(amount))); else if (value->getType()->isDoubleTy()) amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast(amount))); else { llvm::APFloat F(static_cast(amount)); bool ignored; F.convert(CGF.getTarget().getLongDoubleFormat(), llvm::APFloat::rmTowardZero, &ignored); amt = llvm::ConstantFP::get(VMContext, F); } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType && !CGF.getContext().getLangOpts().HalfArgsAndReturns) value = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16, CGF.CGM.FloatTy), value); // Objective-C pointer types. } else { const ObjCObjectPointerType *OPT = type->castAs(); value = CGF.EmitCastToVoidPtr(value); CharUnits size = CGF.getContext().getTypeSizeInChars(OPT->getObjectType()); if (!isInc) size = -size; llvm::Value *sizeValue = llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); else value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); value = Builder.CreateBitCast(value, input->getType()); } if (atomicPHI) { llvm::BasicBlock *opBB = Builder.GetInsertBlock(); llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn); auto Pair = CGF.EmitAtomicCompareExchange( LV, RValue::get(atomicPHI), RValue::get(CGF.EmitToMemory(value, type)), E->getExprLoc()); llvm::Value *old = Pair.first.getScalarVal(); llvm::Value *success = Pair.second.getScalarVal(); atomicPHI->addIncoming(old, opBB); Builder.CreateCondBr(success, contBB, opBB); Builder.SetInsertPoint(contBB); return isPre ? value : input; } // Store the updated result through the lvalue. if (LV.isBitField()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value); else CGF.EmitStoreThroughLValue(RValue::get(value), LV); // If this is a postinc, return the value read from memory, otherwise use the // updated value. return isPre ? value : input; } Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { TestAndClearIgnoreResultAssign(); // Emit unary minus with EmitSub so we handle overflow cases etc. BinOpInfo BinOp; BinOp.RHS = Visit(E->getSubExpr()); if (BinOp.RHS->getType()->isFPOrFPVectorTy()) BinOp.LHS = llvm::ConstantFP::getZeroValueForNegation(BinOp.RHS->getType()); else BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType()); BinOp.Ty = E->getType(); BinOp.Opcode = BO_Sub; BinOp.FPContractable = false; BinOp.E = E; return EmitSub(BinOp); } Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) { TestAndClearIgnoreResultAssign(); Value *Op = Visit(E->getSubExpr()); return Builder.CreateNot(Op, "neg"); } Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { // Perform vector logical not on comparison with zero vector. if (E->getType()->isExtVectorType()) { Value *Oper = Visit(E->getSubExpr()); Value *Zero = llvm::Constant::getNullValue(Oper->getType()); Value *Result; if (Oper->getType()->isFPOrFPVectorTy()) Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp"); else Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext"); } // Compare operand to zero. Value *BoolVal = CGF.EvaluateExprAsBool(E->getSubExpr()); // Invert value. // TODO: Could dynamically modify easy computations here. For example, if // the operand is an icmp ne, turn into icmp eq. BoolVal = Builder.CreateNot(BoolVal, "lnot"); // ZExt result to the expr type. return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { // Try folding the offsetof to a constant. llvm::APSInt Value; if (E->EvaluateAsInt(Value, CGF.getContext())) return Builder.getInt(Value); // Loop over the components of the offsetof to compute the value. unsigned n = E->getNumComponents(); llvm::Type* ResultType = ConvertType(E->getType()); llvm::Value* Result = llvm::Constant::getNullValue(ResultType); QualType CurrentType = E->getTypeSourceInfo()->getType(); for (unsigned i = 0; i != n; ++i) { OffsetOfExpr::OffsetOfNode ON = E->getComponent(i); llvm::Value *Offset = nullptr; switch (ON.getKind()) { case OffsetOfExpr::OffsetOfNode::Array: { // Compute the index Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex()); llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr); bool IdxSigned = IdxExpr->getType()->isSignedIntegerOrEnumerationType(); Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv"); // Save the element type CurrentType = CGF.getContext().getAsArrayType(CurrentType)->getElementType(); // Compute the element size llvm::Value* ElemSize = llvm::ConstantInt::get(ResultType, CGF.getContext().getTypeSizeInChars(CurrentType).getQuantity()); // Multiply out to compute the result Offset = Builder.CreateMul(Idx, ElemSize); break; } case OffsetOfExpr::OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); RecordDecl *RD = CurrentType->getAs()->getDecl(); const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); // Compute the index of the field in its parent. unsigned i = 0; // FIXME: It would be nice if we didn't have to loop here! for (RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++i) { if (*Field == MemberDecl) break; } assert(i < RL.getFieldCount() && "offsetof field in wrong type"); // Compute the offset to the field int64_t OffsetInt = RL.getFieldOffset(i) / CGF.getContext().getCharWidth(); Offset = llvm::ConstantInt::get(ResultType, OffsetInt); // Save the element type. CurrentType = MemberDecl->getType(); break; } case OffsetOfExpr::OffsetOfNode::Identifier: llvm_unreachable("dependent __builtin_offsetof"); case OffsetOfExpr::OffsetOfNode::Base: { if (ON.getBase()->isVirtual()) { CGF.ErrorUnsupported(E, "virtual base in offsetof"); continue; } RecordDecl *RD = CurrentType->getAs()->getDecl(); const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); // Save the element type. CurrentType = ON.getBase()->getType(); // Compute the offset to the base. const RecordType *BaseRT = CurrentType->getAs(); CXXRecordDecl *BaseRD = cast(BaseRT->getDecl()); CharUnits OffsetInt = RL.getBaseClassOffset(BaseRD); Offset = llvm::ConstantInt::get(ResultType, OffsetInt.getQuantity()); break; } } Result = Builder.CreateAdd(Result, Offset); } return Result; } /// VisitUnaryExprOrTypeTraitExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *E) { QualType TypeToSize = E->getTypeOfArgument(); if (E->getKind() == UETT_SizeOf) { if (const VariableArrayType *VAT = CGF.getContext().getAsVariableArrayType(TypeToSize)) { if (E->isArgumentType()) { // sizeof(type) - make sure to emit the VLA size. CGF.EmitVariablyModifiedType(TypeToSize); } else { // C99 6.5.3.4p2: If the argument is an expression of type // VLA, it is evaluated. CGF.EmitIgnoredExpr(E->getArgumentExpr()); } QualType eltType; llvm::Value *numElts; std::tie(numElts, eltType) = CGF.getVLASize(VAT); llvm::Value *size = numElts; // Scale the number of non-VLA elements by the non-VLA element size. CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType); if (!eltSize.isOne()) size = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), numElts); return size; } } // If this isn't sizeof(vla), the result must be constant; use the constant // folding logic so we don't have to duplicate it here. return Builder.getInt(E->EvaluateKnownConstInt(CGF.getContext())); } Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { Expr *Op = E->getSubExpr(); if (Op->getType()->isAnyComplexType()) { // If it's an l-value, load through the appropriate subobject l-value. // Note that we have to ask E because Op might be an l-value that // this won't work for, e.g. an Obj-C property. if (E->isGLValue()) return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc()).getScalarVal(); // Otherwise, calculate and project. return CGF.EmitComplexExpr(Op, false, true).first; } return Visit(Op); } Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { Expr *Op = E->getSubExpr(); if (Op->getType()->isAnyComplexType()) { // If it's an l-value, load through the appropriate subobject l-value. // Note that we have to ask E because Op might be an l-value that // this won't work for, e.g. an Obj-C property. if (Op->isGLValue()) return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc()).getScalarVal(); // Otherwise, calculate and project. return CGF.EmitComplexExpr(Op, true, false).second; } // __imag on a scalar returns zero. Emit the subexpr to ensure side // effects are evaluated, but not the actual value. if (Op->isGLValue()) CGF.EmitLValue(Op); else CGF.EmitScalarExpr(Op, true); return llvm::Constant::getNullValue(ConvertType(E->getType())); } //===----------------------------------------------------------------------===// // Binary Operators //===----------------------------------------------------------------------===// BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { TestAndClearIgnoreResultAssign(); BinOpInfo Result; Result.LHS = Visit(E->getLHS()); Result.RHS = Visit(E->getRHS()); Result.Ty = E->getType(); Result.Opcode = E->getOpcode(); Result.FPContractable = E->isFPContractable(); Result.E = E; return Result; } LValue ScalarExprEmitter::EmitCompoundAssignLValue( const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*Func)(const BinOpInfo &), Value *&Result) { QualType LHSTy = E->getLHS()->getType(); BinOpInfo OpInfo; if (E->getComputationResultType()->isAnyComplexType()) return CGF.EmitScalarCompooundAssignWithComplex(E, Result); // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. OpInfo.RHS = Visit(E->getRHS()); OpInfo.Ty = E->getComputationResultType(); OpInfo.Opcode = E->getOpcode(); OpInfo.FPContractable = false; OpInfo.E = E; // Load/convert the LHS. LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); llvm::PHINode *atomicPHI = nullptr; if (const AtomicType *atomicTy = LHSTy->getAs()) { QualType type = atomicTy->getValueType(); if (!type->isBooleanType() && type->isIntegerType() && !(type->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) && CGF.getLangOpts().getSignedOverflowBehavior() != LangOptions::SOB_Trapping) { llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP; switch (OpInfo.Opcode) { // We don't have atomicrmw operands for *, %, /, <<, >> case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: break; case BO_AddAssign: aop = llvm::AtomicRMWInst::Add; break; case BO_SubAssign: aop = llvm::AtomicRMWInst::Sub; break; case BO_AndAssign: aop = llvm::AtomicRMWInst::And; break; case BO_XorAssign: aop = llvm::AtomicRMWInst::Xor; break; case BO_OrAssign: aop = llvm::AtomicRMWInst::Or; break; default: llvm_unreachable("Invalid compound assignment type"); } if (aop != llvm::AtomicRMWInst::BAD_BINOP) { llvm::Value *amt = CGF.EmitToMemory(EmitScalarConversion(OpInfo.RHS, E->getRHS()->getType(), LHSTy), LHSTy); Builder.CreateAtomicRMW(aop, LHSLV.getAddress(), amt, llvm::SequentiallyConsistent); return LHSLV; } } // FIXME: For floating point types, we should be saving and restoring the // floating point environment in the loop. llvm::BasicBlock *startBB = Builder.GetInsertBlock(); llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn); OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc()); OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type); Builder.CreateBr(opBB); Builder.SetInsertPoint(opBB); atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2); atomicPHI->addIncoming(OpInfo.LHS, startBB); OpInfo.LHS = atomicPHI; } else OpInfo.LHS = EmitLoadOfLValue(LHSLV, E->getExprLoc()); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); // Expand the binary operator. Result = (this->*Func)(OpInfo); // Convert the result back to the LHS type. Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy); if (atomicPHI) { llvm::BasicBlock *opBB = Builder.GetInsertBlock(); llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn); auto Pair = CGF.EmitAtomicCompareExchange( LHSLV, RValue::get(atomicPHI), RValue::get(CGF.EmitToMemory(Result, LHSTy)), E->getExprLoc()); llvm::Value *old = Pair.first.getScalarVal(); llvm::Value *success = Pair.second.getScalarVal(); atomicPHI->addIncoming(old, opBB); Builder.CreateCondBr(success, contBB, opBB); Builder.SetInsertPoint(contBB); return LHSLV; } // Store the result value into the LHS lvalue. Bit-fields are handled // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the // assignment...'. if (LHSLV.isBitField()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, &Result); else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV); return LHSLV; } Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { bool Ignore = TestAndClearIgnoreResultAssign(); Value *RHS; LValue LHS = EmitCompoundAssignLValue(E, Func, RHS); // If the result is clearly ignored, return now. if (Ignore) return nullptr; // The result of an assignment in C is the assigned r-value. if (!CGF.getLangOpts().CPlusPlus) return RHS; // If the lvalue is non-volatile, return the computed value of the assignment. if (!LHS.isVolatileQualified()) return RHS; // Otherwise, reload the value. return EmitLoadOfLValue(LHS, E->getExprLoc()); } void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) { SmallVector, 2> Checks; if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) { Checks.push_back(std::make_pair(Builder.CreateICmpNE(Ops.RHS, Zero), SanitizerKind::IntegerDivideByZero)); } if (CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow) && Ops.Ty->hasSignedIntegerRepresentation()) { llvm::IntegerType *Ty = cast(Zero->getType()); llvm::Value *IntMin = Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth())); llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL); llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin); llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne); llvm::Value *NotOverflow = Builder.CreateOr(LHSCmp, RHSCmp, "or"); Checks.push_back( std::make_pair(NotOverflow, SanitizerKind::SignedIntegerOverflow)); } if (Checks.size() > 0) EmitBinOpCheck(Checks, Ops); } Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { { CodeGenFunction::SanitizerScope SanScope(&CGF); if ((CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero) || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) && Ops.Ty->isIntegerType()) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true); } else if (CGF.SanOpts.has(SanitizerKind::FloatDivideByZero) && Ops.Ty->isRealFloatingType()) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); llvm::Value *NonZero = Builder.CreateFCmpUNE(Ops.RHS, Zero); EmitBinOpCheck(std::make_pair(NonZero, SanitizerKind::FloatDivideByZero), Ops); } } if (Ops.LHS->getType()->isFPOrFPVectorTy()) { llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); if (CGF.getLangOpts().OpenCL) { // OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp llvm::Type *ValTy = Val->getType(); if (ValTy->isFloatTy() || (isa(ValTy) && cast(ValTy)->getElementType()->isFloatTy())) CGF.SetFPAccuracy(Val, 2.5); } return Val; } else if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); else return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div"); } Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. if (CGF.SanOpts.has(SanitizerKind::IntegerDivideByZero)) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); if (Ops.Ty->isIntegerType()) EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false); } if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); else return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { unsigned IID; unsigned OpID = 0; bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType(); switch (Ops.Opcode) { case BO_Add: case BO_AddAssign: OpID = 1; IID = isSigned ? llvm::Intrinsic::sadd_with_overflow : llvm::Intrinsic::uadd_with_overflow; break; case BO_Sub: case BO_SubAssign: OpID = 2; IID = isSigned ? llvm::Intrinsic::ssub_with_overflow : llvm::Intrinsic::usub_with_overflow; break; case BO_Mul: case BO_MulAssign: OpID = 3; IID = isSigned ? llvm::Intrinsic::smul_with_overflow : llvm::Intrinsic::umul_with_overflow; break; default: llvm_unreachable("Unsupported operation for overflow detection"); } OpID <<= 1; if (isSigned) OpID |= 1; llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty); llvm::Function *intrinsic = CGF.CGM.getIntrinsic(IID, opTy); Value *resultAndOverflow = Builder.CreateCall2(intrinsic, Ops.LHS, Ops.RHS); Value *result = Builder.CreateExtractValue(resultAndOverflow, 0); Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1); // Handle overflow with llvm.trap if no custom handler has been specified. const std::string *handlerName = &CGF.getLangOpts().OverflowHandler; if (handlerName->empty()) { // If the signed-integer-overflow sanitizer is enabled, emit a call to its // runtime. Otherwise, this is a -ftrapv check, so just emit a trap. if (!isSigned || CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *NotOverflow = Builder.CreateNot(overflow); SanitizerKind Kind = isSigned ? SanitizerKind::SignedIntegerOverflow : SanitizerKind::UnsignedIntegerOverflow; EmitBinOpCheck(std::make_pair(NotOverflow, Kind), Ops); } else CGF.EmitTrapCheck(Builder.CreateNot(overflow)); return result; } // Branch in case of overflow. llvm::BasicBlock *initialBB = Builder.GetInsertBlock(); llvm::Function::iterator insertPt = initialBB; llvm::BasicBlock *continueBB = CGF.createBasicBlock("nooverflow", CGF.CurFn, std::next(insertPt)); llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn); Builder.CreateCondBr(overflow, overflowBB, continueBB); // If an overflow handler is set, then we want to call it and then use its // result, if it returns. Builder.SetInsertPoint(overflowBB); // Get the overflow handler. llvm::Type *Int8Ty = CGF.Int8Ty; llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty }; llvm::FunctionType *handlerTy = llvm::FunctionType::get(CGF.Int64Ty, argTypes, true); llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName); // Sign extend the args to 64-bit, so that we can use the same handler for // all types of overflow. llvm::Value *lhs = Builder.CreateSExt(Ops.LHS, CGF.Int64Ty); llvm::Value *rhs = Builder.CreateSExt(Ops.RHS, CGF.Int64Ty); // Call the handler with the two arguments, the operation, and the size of // the result. llvm::Value *handlerArgs[] = { lhs, rhs, Builder.getInt8(OpID), Builder.getInt8(cast(opTy)->getBitWidth()) }; llvm::Value *handlerResult = CGF.EmitNounwindRuntimeCall(handler, handlerArgs); // Truncate the result back to the desired size. handlerResult = Builder.CreateTrunc(handlerResult, opTy); Builder.CreateBr(continueBB); Builder.SetInsertPoint(continueBB); llvm::PHINode *phi = Builder.CreatePHI(opTy, 2); phi->addIncoming(result, initialBB); phi->addIncoming(handlerResult, overflowBB); return phi; } /// Emit pointer + index arithmetic. static Value *emitPointerArithmetic(CodeGenFunction &CGF, const BinOpInfo &op, bool isSubtraction) { // Must have binary (not unary) expr here. Unary pointer // increment/decrement doesn't use this path. const BinaryOperator *expr = cast(op.E); Value *pointer = op.LHS; Expr *pointerOperand = expr->getLHS(); Value *index = op.RHS; Expr *indexOperand = expr->getRHS(); // In a subtraction, the LHS is always the pointer. if (!isSubtraction && !pointer->getType()->isPointerTy()) { std::swap(pointer, index); std::swap(pointerOperand, indexOperand); } unsigned width = cast(index->getType())->getBitWidth(); if (width != CGF.PointerWidthInBits) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); index = CGF.Builder.CreateIntCast(index, CGF.PtrDiffTy, isSigned, "idx.ext"); } // If this is subtraction, negate the index. if (isSubtraction) index = CGF.Builder.CreateNeg(index, "idx.neg"); if (CGF.SanOpts.has(SanitizerKind::ArrayBounds)) CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(), /*Accessed*/ false); const PointerType *pointerType = pointerOperand->getType()->getAs(); if (!pointerType) { QualType objectType = pointerOperand->getType() ->castAs() ->getPointeeType(); llvm::Value *objectSize = CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(objectType)); index = CGF.Builder.CreateMul(index, objectSize); Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy); result = CGF.Builder.CreateGEP(result, index, "add.ptr"); return CGF.Builder.CreateBitCast(result, pointer->getType()); } QualType elementType = pointerType->getPointeeType(); if (const VariableArrayType *vla = CGF.getContext().getAsVariableArrayType(elementType)) { // The element count here is the total number of non-VLA elements. llvm::Value *numElements = CGF.getVLASize(vla).first; // Effectively, the multiply by the VLA size is part of the GEP. // GEP indexes are signed, and scaling an index isn't permitted to // signed-overflow, so we use the same semantics for our explicit // multiply. We suppress this if overflow is not undefined behavior. if (CGF.getLangOpts().isSignedOverflowDefined()) { index = CGF.Builder.CreateMul(index, numElements, "vla.index"); pointer = CGF.Builder.CreateGEP(pointer, index, "add.ptr"); } else { index = CGF.Builder.CreateNSWMul(index, numElements, "vla.index"); pointer = CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); } return pointer; } // Explicitly handle GNU void* and function pointer arithmetic extensions. The // GNU void* casts amount to no-ops since our void* type is i8*, but this is // future proof. if (elementType->isVoidType() || elementType->isFunctionType()) { Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy); result = CGF.Builder.CreateGEP(result, index, "add.ptr"); return CGF.Builder.CreateBitCast(result, pointer->getType()); } if (CGF.getLangOpts().isSignedOverflowDefined()) return CGF.Builder.CreateGEP(pointer, index, "add.ptr"); return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); } // Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and // Addend. Use negMul and negAdd to negate the first operand of the Mul or // the add operand respectively. This allows fmuladd to represent a*b-c, or // c-a*b. Patterns in LLVM should catch the negated forms and translate them to // efficient operations. static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend, const CodeGenFunction &CGF, CGBuilderTy &Builder, bool negMul, bool negAdd) { assert(!(negMul && negAdd) && "Only one of negMul and negAdd should be set."); Value *MulOp0 = MulOp->getOperand(0); Value *MulOp1 = MulOp->getOperand(1); if (negMul) { MulOp0 = Builder.CreateFSub( llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0, "neg"); } else if (negAdd) { Addend = Builder.CreateFSub( llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend, "neg"); } Value *FMulAdd = Builder.CreateCall3( CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()), MulOp0, MulOp1, Addend); MulOp->eraseFromParent(); return FMulAdd; } // Check whether it would be legal to emit an fmuladd intrinsic call to // represent op and if so, build the fmuladd. // // Checks that (a) the operation is fusable, and (b) -ffp-contract=on. // Does NOT check the type of the operation - it's assumed that this function // will be called from contexts where it's known that the type is contractable. static Value* tryEmitFMulAdd(const BinOpInfo &op, const CodeGenFunction &CGF, CGBuilderTy &Builder, bool isSub=false) { assert((op.Opcode == BO_Add || op.Opcode == BO_AddAssign || op.Opcode == BO_Sub || op.Opcode == BO_SubAssign) && "Only fadd/fsub can be the root of an fmuladd."); // Check whether this op is marked as fusable. if (!op.FPContractable) return nullptr; // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is // either disabled, or handled entirely by the LLVM backend). if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On) return nullptr; // We have a potentially fusable op. Look for a mul on one of the operands. if (llvm::BinaryOperator* LHSBinOp = dyn_cast(op.LHS)) { if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) { assert(LHSBinOp->getNumUses() == 0 && "Operations with multiple uses shouldn't be contracted."); return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub); } } else if (llvm::BinaryOperator* RHSBinOp = dyn_cast(op.RHS)) { if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) { assert(RHSBinOp->getNumUses() == 0 && "Operations with multiple uses shouldn't be contracted."); return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false); } } return nullptr; } Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.LHS->getType()->isPointerTy() || op.RHS->getType()->isPointerTy()) return emitPointerArithmetic(CGF, op, /*subtraction*/ false); if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateAdd(op.LHS, op.RHS, "add"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } } if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) return EmitOverflowCheckedBinOp(op); if (op.LHS->getType()->isFPOrFPVectorTy()) { // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) return FMulAdd; return Builder.CreateFAdd(op.LHS, op.RHS, "add"); } return Builder.CreateAdd(op.LHS, op.RHS, "add"); } Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { // The LHS is always a pointer if either side is. if (!op.LHS->getType()->isPointerTy()) { if (op.Ty->isSignedIntegerOrEnumerationType()) { switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateSub(op.LHS, op.RHS, "sub"); case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } } if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) return EmitOverflowCheckedBinOp(op); if (op.LHS->getType()->isFPOrFPVectorTy()) { // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) return FMulAdd; return Builder.CreateFSub(op.LHS, op.RHS, "sub"); } return Builder.CreateSub(op.LHS, op.RHS, "sub"); } // If the RHS is not a pointer, then we have normal pointer // arithmetic. if (!op.RHS->getType()->isPointerTy()) return emitPointerArithmetic(CGF, op, /*subtraction*/ true); // Otherwise, this is a pointer subtraction. // Do the raw subtraction part. llvm::Value *LHS = Builder.CreatePtrToInt(op.LHS, CGF.PtrDiffTy, "sub.ptr.lhs.cast"); llvm::Value *RHS = Builder.CreatePtrToInt(op.RHS, CGF.PtrDiffTy, "sub.ptr.rhs.cast"); Value *diffInChars = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); // Okay, figure out the element size. const BinaryOperator *expr = cast(op.E); QualType elementType = expr->getLHS()->getType()->getPointeeType(); llvm::Value *divisor = nullptr; // For a variable-length array, this is going to be non-constant. if (const VariableArrayType *vla = CGF.getContext().getAsVariableArrayType(elementType)) { llvm::Value *numElements; std::tie(numElements, elementType) = CGF.getVLASize(vla); divisor = numElements; // Scale the number of non-VLA elements by the non-VLA element size. CharUnits eltSize = CGF.getContext().getTypeSizeInChars(elementType); if (!eltSize.isOne()) divisor = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), divisor); // For everything elese, we can just compute it, safe in the // assumption that Sema won't let anything through that we can't // safely compute the size of. } else { CharUnits elementSize; // Handle GCC extension for pointer arithmetic on void* and // function pointer types. if (elementType->isVoidType() || elementType->isFunctionType()) elementSize = CharUnits::One(); else elementSize = CGF.getContext().getTypeSizeInChars(elementType); // Don't even emit the divide for element size of 1. if (elementSize.isOne()) return diffInChars; divisor = CGF.CGM.getSize(elementSize); } // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since // pointer difference in C is only defined in the case where both operands // are pointing to elements of an array. return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div"); } Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) { llvm::IntegerType *Ty; if (llvm::VectorType *VT = dyn_cast(LHS->getType())) Ty = cast(VT->getElementType()); else Ty = cast(LHS->getType()); return llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth() - 1); } Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { // LLVM requires the LHS and RHS to be the same type: promote or truncate the // RHS to the same size as the LHS. Value *RHS = Ops.RHS; if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL && isa(Ops.LHS->getType())) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS); llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne); if (Ops.Ty->hasSignedIntegerRepresentation()) { llvm::BasicBlock *Orig = Builder.GetInsertBlock(); llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); llvm::BasicBlock *CheckBitsShifted = CGF.createBasicBlock("check"); Builder.CreateCondBr(Valid, CheckBitsShifted, Cont); // Check whether we are shifting any non-zero bits off the top of the // integer. CGF.EmitBlock(CheckBitsShifted); llvm::Value *BitsShiftedOff = Builder.CreateLShr(Ops.LHS, Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros", /*NUW*/true, /*NSW*/true), "shl.check"); if (CGF.getLangOpts().CPlusPlus) { // In C99, we are not permitted to shift a 1 bit into the sign bit. // Under C++11's rules, shifting a 1 bit into the sign bit is // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't // define signed left shifts, so we use the C99 and C++11 rules there). llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1); BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One); } llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0); llvm::Value *SecondCheck = Builder.CreateICmpEQ(BitsShiftedOff, Zero); CGF.EmitBlock(Cont); llvm::PHINode *P = Builder.CreatePHI(Valid->getType(), 2); P->addIncoming(Valid, Orig); P->addIncoming(SecondCheck, CheckBitsShifted); Valid = P; } EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops); } // OpenCL 6.3j: shift values are effectively % word size of LHS. if (CGF.getLangOpts().OpenCL) RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask"); return Builder.CreateShl(Ops.LHS, RHS, "shl"); } Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { // LLVM requires the LHS and RHS to be the same type: promote or truncate the // RHS to the same size as the LHS. Value *RHS = Ops.RHS; if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); if (CGF.SanOpts.has(SanitizerKind::Shift) && !CGF.getLangOpts().OpenCL && isa(Ops.LHS->getType())) { CodeGenFunction::SanitizerScope SanScope(&CGF); llvm::Value *Valid = Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)); EmitBinOpCheck(std::make_pair(Valid, SanitizerKind::Shift), Ops); } // OpenCL 6.3j: shift values are effectively % word size of LHS. if (CGF.getLangOpts().OpenCL) RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask"); if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); } enum IntrinsicType { VCMPEQ, VCMPGT }; // return corresponding comparison intrinsic for given vector type static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT, BuiltinType::Kind ElemKind) { switch (ElemKind) { default: llvm_unreachable("unexpected element type"); case BuiltinType::Char_U: case BuiltinType::UChar: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p : llvm::Intrinsic::ppc_altivec_vcmpgtub_p; case BuiltinType::Char_S: case BuiltinType::SChar: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p : llvm::Intrinsic::ppc_altivec_vcmpgtsb_p; case BuiltinType::UShort: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p : llvm::Intrinsic::ppc_altivec_vcmpgtuh_p; case BuiltinType::Short: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p : llvm::Intrinsic::ppc_altivec_vcmpgtsh_p; case BuiltinType::UInt: case BuiltinType::ULong: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : llvm::Intrinsic::ppc_altivec_vcmpgtuw_p; case BuiltinType::Int: case BuiltinType::Long: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : llvm::Intrinsic::ppc_altivec_vcmpgtsw_p; case BuiltinType::Float: return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p : llvm::Intrinsic::ppc_altivec_vcmpgtfp_p; } } Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, unsigned SICmpOpc, unsigned FCmpOpc) { TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); QualType RHSTy = E->getRHS()->getType(); if (const MemberPointerType *MPT = LHSTy->getAs()) { assert(E->getOpcode() == BO_EQ || E->getOpcode() == BO_NE); Value *LHS = CGF.EmitScalarExpr(E->getLHS()); Value *RHS = CGF.EmitScalarExpr(E->getRHS()); Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison( CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE); } else if (!LHSTy->isAnyComplexType() && !RHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); // If AltiVec, the comparison results in a numeric type, so we use // intrinsics comparing vectors and giving 0 or 1 as a result if (LHSTy->isVectorType() && !E->getType()->isVectorType()) { // constants for mapping CR6 register bits to predicate result enum { CR6_EQ=0, CR6_EQ_REV, CR6_LT, CR6_LT_REV } CR6; llvm::Intrinsic::ID ID = llvm::Intrinsic::not_intrinsic; // in several cases vector arguments order will be reversed Value *FirstVecArg = LHS, *SecondVecArg = RHS; QualType ElTy = LHSTy->getAs()->getElementType(); const BuiltinType *BTy = ElTy->getAs(); BuiltinType::Kind ElementKind = BTy->getKind(); switch(E->getOpcode()) { default: llvm_unreachable("is not a comparison operation"); case BO_EQ: CR6 = CR6_LT; ID = GetIntrinsic(VCMPEQ, ElementKind); break; case BO_NE: CR6 = CR6_EQ; ID = GetIntrinsic(VCMPEQ, ElementKind); break; case BO_LT: CR6 = CR6_LT; ID = GetIntrinsic(VCMPGT, ElementKind); std::swap(FirstVecArg, SecondVecArg); break; case BO_GT: CR6 = CR6_LT; ID = GetIntrinsic(VCMPGT, ElementKind); break; case BO_LE: if (ElementKind == BuiltinType::Float) { CR6 = CR6_LT; ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p; std::swap(FirstVecArg, SecondVecArg); } else { CR6 = CR6_EQ; ID = GetIntrinsic(VCMPGT, ElementKind); } break; case BO_GE: if (ElementKind == BuiltinType::Float) { CR6 = CR6_LT; ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p; } else { CR6 = CR6_EQ; ID = GetIntrinsic(VCMPGT, ElementKind); std::swap(FirstVecArg, SecondVecArg); } break; } Value *CR6Param = Builder.getInt32(CR6); llvm::Function *F = CGF.CGM.getIntrinsic(ID); Result = Builder.CreateCall3(F, CR6Param, FirstVecArg, SecondVecArg, ""); return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType()); } if (LHS->getType()->isFPOrFPVectorTy()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); } else if (LHSTy->hasSignedIntegerRepresentation()) { Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc, LHS, RHS, "cmp"); } else { // Unsigned integers and pointers. Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, LHS, RHS, "cmp"); } // If this is a vector comparison, sign extend the result to the appropriate // vector integer type and return it (don't convert to bool). if (LHSTy->isVectorType()) return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext"); } else { // Complex Comparison: can only be an equality comparison. CodeGenFunction::ComplexPairTy LHS, RHS; QualType CETy; if (auto *CTy = LHSTy->getAs()) { LHS = CGF.EmitComplexExpr(E->getLHS()); CETy = CTy->getElementType(); } else { LHS.first = Visit(E->getLHS()); LHS.second = llvm::Constant::getNullValue(LHS.first->getType()); CETy = LHSTy; } if (auto *CTy = RHSTy->getAs()) { RHS = CGF.EmitComplexExpr(E->getRHS()); assert(CGF.getContext().hasSameUnqualifiedType(CETy, CTy->getElementType()) && "The element types must always match."); (void)CTy; } else { RHS.first = Visit(E->getRHS()); RHS.second = llvm::Constant::getNullValue(RHS.first->getType()); assert(CGF.getContext().hasSameUnqualifiedType(CETy, RHSTy) && "The element types must always match."); } Value *ResultR, *ResultI; if (CETy->isRealFloatingType()) { ResultR = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, LHS.first, RHS.first, "cmp.r"); ResultI = Builder.CreateFCmp((llvm::FCmpInst::Predicate)FCmpOpc, LHS.second, RHS.second, "cmp.i"); } else { // Complex comparisons can only be equality comparisons. As such, signed // and unsigned opcodes are the same. ResultR = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, LHS.first, RHS.first, "cmp.r"); ResultI = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, LHS.second, RHS.second, "cmp.i"); } if (E->getOpcode() == BO_EQ) { Result = Builder.CreateAnd(ResultR, ResultI, "and.ri"); } else { assert(E->getOpcode() == BO_NE && "Complex comparison other than == or != ?"); Result = Builder.CreateOr(ResultR, ResultI, "or.ri"); } } return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType()); } Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { bool Ignore = TestAndClearIgnoreResultAssign(); Value *RHS; LValue LHS; switch (E->getLHS()->getType().getObjCLifetime()) { case Qualifiers::OCL_Strong: std::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore); break; case Qualifiers::OCL_Autoreleasing: std::tie(LHS, RHS) = CGF.EmitARCStoreAutoreleasing(E); break; case Qualifiers::OCL_Weak: RHS = Visit(E->getRHS()); LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore); break; // No reason to do any of these differently. case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: // __block variables need to have the rhs evaluated first, plus // this should improve codegen just a little. RHS = Visit(E->getRHS()); LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); // Store the value into the LHS. Bit-fields are handled specially // because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after // the assignment...'. if (LHS.isBitField()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS); else CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS); } // If the result is clearly ignored, return now. if (Ignore) return nullptr; // The result of an assignment in C is the assigned r-value. if (!CGF.getLangOpts().CPlusPlus) return RHS; // If the lvalue is non-volatile, return the computed value of the assignment. if (!LHS.isVolatileQualified()) return RHS; // Otherwise, reload the value. return EmitLoadOfLValue(LHS, E->getExprLoc()); } Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { RegionCounter Cnt = CGF.getPGORegionCounter(E); // Perform vector logical and on comparisons with zero vectors. if (E->getType()->isVectorType()) { Cnt.beginRegion(Builder); Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); } Value *And = Builder.CreateAnd(LHS, RHS); return Builder.CreateSExt(And, ConvertType(E->getType()), "sext"); } llvm::Type *ResTy = ConvertType(E->getType()); // If we have 0 && RHS, see if we can elide RHS, if so, just return 0. // If we have 1 && X, just emit X without inserting the control flow. bool LHSCondVal; if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) { if (LHSCondVal) { // If we have 1 && X, just emit X. Cnt.beginRegion(Builder); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); // ZExt result to int or bool. return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext"); } // 0 && RHS: If it is safe, just elide the RHS, and return 0/false. if (!CGF.ContainsLabel(E->getRHS())) return llvm::Constant::getNullValue(ResTy); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("land.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("land.rhs"); CodeGenFunction::ConditionalEvaluation eval(CGF); // Branch on the LHS first. If it is false, go to the failure (cont) block. CGF.EmitBranchOnBoolExpr(E->getLHS(), RHSBlock, ContBlock, Cnt.getCount()); // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be false. Start // setting up the PHI node in the Cont Block for this. llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2, "", ContBlock); for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); eval.begin(CGF); CGF.EmitBlock(RHSBlock); Cnt.beginRegion(Builder); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); eval.end(CGF); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); // Emit an unconditional branch from this block to ContBlock. { // There is no need to emit line number for unconditional branch. ApplyDebugLocation DL(CGF); CGF.EmitBlock(ContBlock); } // Insert an entry into the phi node for the edge with the value of RHSCond. PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. return Builder.CreateZExtOrBitCast(PN, ResTy, "land.ext"); } Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { RegionCounter Cnt = CGF.getPGORegionCounter(E); // Perform vector logical or on comparisons with zero vectors. if (E->getType()->isVectorType()) { Cnt.beginRegion(Builder); Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); } Value *Or = Builder.CreateOr(LHS, RHS); return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext"); } llvm::Type *ResTy = ConvertType(E->getType()); // If we have 1 || RHS, see if we can elide RHS, if so, just return 1. // If we have 0 || X, just emit X without inserting the control flow. bool LHSCondVal; if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) { if (!LHSCondVal) { // If we have 0 || X, just emit X. Cnt.beginRegion(Builder); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); // ZExt result to int or bool. return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext"); } // 1 || RHS: If it is safe, just elide the RHS, and return 1/true. if (!CGF.ContainsLabel(E->getRHS())) return llvm::ConstantInt::get(ResTy, 1); } llvm::BasicBlock *ContBlock = CGF.createBasicBlock("lor.end"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("lor.rhs"); CodeGenFunction::ConditionalEvaluation eval(CGF); // Branch on the LHS first. If it is true, go to the success (cont) block. CGF.EmitBranchOnBoolExpr(E->getLHS(), ContBlock, RHSBlock, Cnt.getParentCount() - Cnt.getCount()); // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be true. Start // setting up the PHI node in the Cont Block for this. llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2, "", ContBlock); for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); eval.begin(CGF); // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Cnt.beginRegion(Builder); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); eval.end(CGF); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); // Emit an unconditional branch from this block to ContBlock. Insert an entry // into the phi node for the edge with the value of RHSCond. CGF.EmitBlock(ContBlock); PN->addIncoming(RHSCond, RHSBlock); // ZExt result to int. return Builder.CreateZExtOrBitCast(PN, ResTy, "lor.ext"); } Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { CGF.EmitIgnoredExpr(E->getLHS()); CGF.EnsureInsertPoint(); return Visit(E->getRHS()); } //===----------------------------------------------------------------------===// // Other Operators //===----------------------------------------------------------------------===// /// isCheapEnoughToEvaluateUnconditionally - Return true if the specified /// expression is cheap enough and side-effect-free enough to evaluate /// unconditionally instead of conditionally. This is used to convert control /// flow into selects in some cases. static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, CodeGenFunction &CGF) { // Anything that is an integer or floating point constant is fine. return E->IgnoreParens()->isEvaluatable(CGF.getContext()); // Even non-volatile automatic variables can't be evaluated unconditionally. // Referencing a thread_local may cause non-trivial initialization work to // occur. If we're inside a lambda and one of the variables is from the scope // outside the lambda, that function may have returned already. Reading its // locals is a bad idea. Also, these reads may introduce races there didn't // exist in the source-level program. } Value *ScalarExprEmitter:: VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { TestAndClearIgnoreResultAssign(); // Bind the common expression if necessary. CodeGenFunction::OpaqueValueMapping binding(CGF, E); RegionCounter Cnt = CGF.getPGORegionCounter(E); Expr *condExpr = E->getCond(); Expr *lhsExpr = E->getTrueExpr(); Expr *rhsExpr = E->getFalseExpr(); // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm. bool CondExprBool; if (CGF.ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) { Expr *live = lhsExpr, *dead = rhsExpr; if (!CondExprBool) std::swap(live, dead); // If the dead side doesn't have labels we need, just emit the Live part. if (!CGF.ContainsLabel(dead)) { if (CondExprBool) Cnt.beginRegion(Builder); Value *Result = Visit(live); // If the live part is a throw expression, it acts like it has a void // type, so evaluating it returns a null Value*. However, a conditional // with non-void type must return a non-null Value*. if (!Result && !E->getType()->isVoidType()) Result = llvm::UndefValue::get(CGF.ConvertType(E->getType())); return Result; } } // OpenCL: If the condition is a vector, we can treat this condition like // the select function. if (CGF.getLangOpts().OpenCL && condExpr->getType()->isVectorType()) { Cnt.beginRegion(Builder); llvm::Value *CondV = CGF.EmitScalarExpr(condExpr); llvm::Value *LHS = Visit(lhsExpr); llvm::Value *RHS = Visit(rhsExpr); llvm::Type *condType = ConvertType(condExpr->getType()); llvm::VectorType *vecTy = cast(condType); unsigned numElem = vecTy->getNumElements(); llvm::Type *elemType = vecTy->getElementType(); llvm::Value *zeroVec = llvm::Constant::getNullValue(vecTy); llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec); llvm::Value *tmp = Builder.CreateSExt(TestMSB, llvm::VectorType::get(elemType, numElem), "sext"); llvm::Value *tmp2 = Builder.CreateNot(tmp); // Cast float to int to perform ANDs if necessary. llvm::Value *RHSTmp = RHS; llvm::Value *LHSTmp = LHS; bool wasCast = false; llvm::VectorType *rhsVTy = cast(RHS->getType()); if (rhsVTy->getElementType()->isFloatingPointTy()) { RHSTmp = Builder.CreateBitCast(RHS, tmp2->getType()); LHSTmp = Builder.CreateBitCast(LHS, tmp->getType()); wasCast = true; } llvm::Value *tmp3 = Builder.CreateAnd(RHSTmp, tmp2); llvm::Value *tmp4 = Builder.CreateAnd(LHSTmp, tmp); llvm::Value *tmp5 = Builder.CreateOr(tmp3, tmp4, "cond"); if (wasCast) tmp5 = Builder.CreateBitCast(tmp5, RHS->getType()); return tmp5; } // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. if (isCheapEnoughToEvaluateUnconditionally(lhsExpr, CGF) && isCheapEnoughToEvaluateUnconditionally(rhsExpr, CGF)) { Cnt.beginRegion(Builder); llvm::Value *CondV = CGF.EvaluateExprAsBool(condExpr); llvm::Value *LHS = Visit(lhsExpr); llvm::Value *RHS = Visit(rhsExpr); if (!LHS) { // If the conditional has void type, make sure we return a null Value*. assert(!RHS && "LHS and RHS types must match"); return nullptr; } return Builder.CreateSelect(CondV, LHS, RHS, "cond"); } llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); CodeGenFunction::ConditionalEvaluation eval(CGF); CGF.EmitBranchOnBoolExpr(condExpr, LHSBlock, RHSBlock, Cnt.getCount()); CGF.EmitBlock(LHSBlock); Cnt.beginRegion(Builder); eval.begin(CGF); Value *LHS = Visit(lhsExpr); eval.end(CGF); LHSBlock = Builder.GetInsertBlock(); Builder.CreateBr(ContBlock); CGF.EmitBlock(RHSBlock); eval.begin(CGF); Value *RHS = Visit(rhsExpr); eval.end(CGF); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBlock(ContBlock); // If the LHS or RHS is a throw expression, it will be legitimately null. if (!LHS) return RHS; if (!RHS) return LHS; // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond"); PN->addIncoming(LHS, LHSBlock); PN->addIncoming(RHS, RHSBlock); return PN; } Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { return Visit(E->getChosenSubExpr()); } Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { QualType Ty = VE->getType(); if (Ty->isVariablyModifiedType()) CGF.EmitVariablyModifiedType(Ty); llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr()); llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType()); llvm::Type *ArgTy = ConvertType(VE->getType()); // If EmitVAArg fails, we fall back to the LLVM instruction. if (!ArgPtr) return Builder.CreateVAArg(ArgValue, ArgTy); // FIXME Volatility. llvm::Value *Val = Builder.CreateLoad(ArgPtr); // If EmitVAArg promoted the type, we must truncate it. if (ArgTy != Val->getType()) { if (ArgTy->isPointerTy() && !Val->getType()->isPointerTy()) Val = Builder.CreateIntToPtr(Val, ArgTy); else Val = Builder.CreateTrunc(Val, ArgTy); } return Val; } Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) { return CGF.EmitBlockLiteral(block); } Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); llvm::Type *DstTy = ConvertType(E->getType()); // Going from vec4->vec3 or vec3->vec4 is a special case and requires // a shuffle vector instead of a bitcast. llvm::Type *SrcTy = Src->getType(); if (isa(DstTy) && isa(SrcTy)) { unsigned numElementsDst = cast(DstTy)->getNumElements(); unsigned numElementsSrc = cast(SrcTy)->getNumElements(); if ((numElementsDst == 3 && numElementsSrc == 4) || (numElementsDst == 4 && numElementsSrc == 3)) { // In the case of going from int4->float3, a bitcast is needed before // doing a shuffle. llvm::Type *srcElemTy = cast(SrcTy)->getElementType(); llvm::Type *dstElemTy = cast(DstTy)->getElementType(); if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy()) || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) { // Create a float type of the same size as the source or destination. llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, numElementsSrc); Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); } llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); SmallVector Args; Args.push_back(Builder.getInt32(0)); Args.push_back(Builder.getInt32(1)); Args.push_back(Builder.getInt32(2)); if (numElementsDst == 4) Args.push_back(llvm::UndefValue::get(CGF.Int32Ty)); llvm::Constant *Mask = llvm::ConstantVector::get(Args); return Builder.CreateShuffleVector(Src, UnV, Mask, "astype"); } } return Builder.CreateBitCast(Src, DstTy, "astype"); } Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) { return CGF.EmitAtomicExpr(E).getScalarVal(); } //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// /// EmitScalarExpr - Emit the computation of the specified expression of scalar /// type, ignoring the result. Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) { assert(E && hasScalarEvaluationKind(E->getType()) && "Invalid scalar expression to emit"); + bool hasDebugInfo = getDebugInfo(); if (isa(E)) disableDebugInfo(); Value *V = ScalarExprEmitter(*this, IgnoreResultAssign) .Visit(const_cast(E)); - if (isa(E)) + if (isa(E) && hasDebugInfo) enableDebugInfo(); return V; } /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy) { assert(hasScalarEvaluationKind(SrcTy) && hasScalarEvaluationKind(DstTy) && "Invalid scalar expression to emit"); return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy); } /// EmitComplexToScalarConversion - Emit a conversion from the specified complex /// type to the specified destination type, where the destination type is an /// LLVM scalar type. Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy, QualType DstTy) { assert(SrcTy->isAnyComplexType() && hasScalarEvaluationKind(DstTy) && "Invalid complex -> scalar conversion"); return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy, DstTy); } llvm::Value *CodeGenFunction:: EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { return ScalarExprEmitter(*this).EmitScalarPrePostIncDec(E, LV, isInc, isPre); } LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { llvm::Value *V; // object->isa or (*object).isa // Generate code as for: *(Class*)object // build Class* type llvm::Type *ClassPtrTy = ConvertType(E->getType()); Expr *BaseExpr = E->getBase(); if (BaseExpr->isRValue()) { V = CreateMemTemp(E->getType(), "resval"); llvm::Value *Src = EmitScalarExpr(BaseExpr); Builder.CreateStore(Src, V); V = ScalarExprEmitter(*this).EmitLoadOfLValue( MakeNaturalAlignAddrLValue(V, E->getType()), E->getExprLoc()); } else { if (E->isArrow()) V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); else V = EmitLValue(BaseExpr).getAddress(); } // build Class* type ClassPtrTy = ClassPtrTy->getPointerTo(); V = Builder.CreateBitCast(V, ClassPtrTy); return MakeNaturalAlignAddrLValue(V, E->getType()); } LValue CodeGenFunction::EmitCompoundAssignmentLValue( const CompoundAssignOperator *E) { ScalarExprEmitter Scalar(*this); Value *Result = nullptr; switch (E->getOpcode()) { #define COMPOUND_OP(Op) \ case BO_##Op##Assign: \ return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \ Result) COMPOUND_OP(Mul); COMPOUND_OP(Div); COMPOUND_OP(Rem); COMPOUND_OP(Add); COMPOUND_OP(Sub); COMPOUND_OP(Shl); COMPOUND_OP(Shr); COMPOUND_OP(And); COMPOUND_OP(Xor); COMPOUND_OP(Or); #undef COMPOUND_OP case BO_PtrMemD: case BO_PtrMemI: case BO_Mul: case BO_Div: case BO_Rem: case BO_Add: case BO_Sub: case BO_Shl: case BO_Shr: case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: case BO_And: case BO_Xor: case BO_Or: case BO_LAnd: case BO_LOr: case BO_Assign: case BO_Comma: llvm_unreachable("Not valid compound assignment operators"); } llvm_unreachable("Unhandled compound assignment operator"); } Index: vendor/clang/dist/lib/CodeGen/CodeGenModule.cpp =================================================================== --- vendor/clang/dist/lib/CodeGen/CodeGenModule.cpp (revision 278753) +++ vendor/clang/dist/lib/CodeGen/CodeGenModule.cpp (revision 278754) @@ -1,3592 +1,3592 @@ //===--- CodeGenModule.cpp - Emit LLVM Code from ASTs for a Module --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This coordinates the per-module state used while generating code. // //===----------------------------------------------------------------------===// #include "CodeGenModule.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGCall.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenPGO.h" #include "CodeGenTBAA.h" #include "CoverageMappingGen.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI *createCXXABI(CodeGenModule &CGM) { switch (CGM.getTarget().getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: case TargetCXXABI::iOS64: case TargetCXXABI::GenericItanium: return CreateItaniumCXXABI(CGM); case TargetCXXABI::Microsoft: return CreateMicrosoftCXXABI(CGM); } llvm_unreachable("invalid C++ ABI kind"); } CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &diags, CoverageSourceInfo *CoverageInfo) : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M), Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()), ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(nullptr), TheTargetCodeGenInfo(nullptr), Types(*this), VTables(*this), ObjCRuntime(nullptr), OpenCLRuntime(nullptr), OpenMPRuntime(nullptr), CUDARuntime(nullptr), DebugInfo(nullptr), ARCData(nullptr), NoObjCARCExceptionsMetadata(nullptr), RRData(nullptr), PGOReader(nullptr), CFConstantStringClassRef(nullptr), ConstantStringClassRef(nullptr), NSConstantStringType(nullptr), NSConcreteGlobalBlock(nullptr), NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr), BlockObjectDispose(nullptr), BlockDescriptorType(nullptr), GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr), LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)) { // Initialize the type cache. llvm::LLVMContext &LLVMContext = M.getContext(); VoidTy = llvm::Type::getVoidTy(LLVMContext); Int8Ty = llvm::Type::getInt8Ty(LLVMContext); Int16Ty = llvm::Type::getInt16Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); FloatTy = llvm::Type::getFloatTy(LLVMContext); DoubleTy = llvm::Type::getDoubleTy(LLVMContext); PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); PointerAlignInBytes = C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity(); IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth()); IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC(); BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC(); if (LangOpts.ObjC1) createObjCRuntime(); if (LangOpts.OpenCL) createOpenCLRuntime(); if (LangOpts.OpenMP) createOpenMPRuntime(); if (LangOpts.CUDA) createCUDARuntime(); // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. if (LangOpts.Sanitize.has(SanitizerKind::Thread) || (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)) TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(), getCXXABI().getMangleContext()); // If debug info or coverage generation is enabled, create the CGDebugInfo // object. if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo || CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) DebugInfo = new CGDebugInfo(*this); Block.GlobalUniqueCount = 0; if (C.getLangOpts().ObjCAutoRefCount) ARCData = new ARCEntrypoints(); RRData = new RREntrypoints(); if (!CodeGenOpts.InstrProfileInput.empty()) { if (std::error_code EC = llvm::IndexedInstrProfReader::create( CodeGenOpts.InstrProfileInput, PGOReader)) { unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "Could not read profile: %0"); getDiags().Report(DiagID) << EC.message(); } } // If coverage mapping generation is enabled, create the // CoverageMappingModuleGen object. if (CodeGenOpts.CoverageMapping) CoverageMapping.reset(new CoverageMappingModuleGen(*this, *CoverageInfo)); } CodeGenModule::~CodeGenModule() { delete ObjCRuntime; delete OpenCLRuntime; delete OpenMPRuntime; delete CUDARuntime; delete TheTargetCodeGenInfo; delete TBAA; delete DebugInfo; delete ARCData; delete RRData; } void CodeGenModule::createObjCRuntime() { // This is just isGNUFamily(), but we want to force implementors of // new ABIs to decide how best to do this. switch (LangOpts.ObjCRuntime.getKind()) { case ObjCRuntime::GNUstep: case ObjCRuntime::GCC: case ObjCRuntime::ObjFW: ObjCRuntime = CreateGNUObjCRuntime(*this); return; case ObjCRuntime::FragileMacOSX: case ObjCRuntime::MacOSX: case ObjCRuntime::iOS: ObjCRuntime = CreateMacObjCRuntime(*this); return; } llvm_unreachable("bad runtime kind"); } void CodeGenModule::createOpenCLRuntime() { OpenCLRuntime = new CGOpenCLRuntime(*this); } void CodeGenModule::createOpenMPRuntime() { OpenMPRuntime = new CGOpenMPRuntime(*this); } void CodeGenModule::createCUDARuntime() { CUDARuntime = CreateNVCUDARuntime(*this); } void CodeGenModule::addReplacement(StringRef Name, llvm::Constant *C) { Replacements[Name] = C; } void CodeGenModule::applyReplacements() { for (ReplacementsTy::iterator I = Replacements.begin(), E = Replacements.end(); I != E; ++I) { StringRef MangledName = I->first(); llvm::Constant *Replacement = I->second; llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (!Entry) continue; auto *OldF = cast(Entry); auto *NewF = dyn_cast(Replacement); if (!NewF) { if (auto *Alias = dyn_cast(Replacement)) { NewF = dyn_cast(Alias->getAliasee()); } else { auto *CE = cast(Replacement); assert(CE->getOpcode() == llvm::Instruction::BitCast || CE->getOpcode() == llvm::Instruction::GetElementPtr); NewF = dyn_cast(CE->getOperand(0)); } } // Replace old with new, but keep the old order. OldF->replaceAllUsesWith(Replacement); if (NewF) { NewF->removeFromParent(); OldF->getParent()->getFunctionList().insertAfter(OldF, NewF); } OldF->eraseFromParent(); } } // This is only used in aliases that we created and we know they have a // linear structure. static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) { llvm::SmallPtrSet Visited; const llvm::Constant *C = &GA; for (;;) { C = C->stripPointerCasts(); if (auto *GO = dyn_cast(C)) return GO; // stripPointerCasts will not walk over weak aliases. auto *GA2 = dyn_cast(C); if (!GA2) return nullptr; if (!Visited.insert(GA2).second) return nullptr; C = GA2->getAliasee(); } } void CodeGenModule::checkAliases() { // Check if the constructed aliases are well formed. It is really unfortunate // that we have to do this in CodeGen, but we only construct mangled names // and aliases during codegen. bool Error = false; DiagnosticsEngine &Diags = getDiags(); for (std::vector::iterator I = Aliases.begin(), E = Aliases.end(); I != E; ++I) { const GlobalDecl &GD = *I; const auto *D = cast(GD.getDecl()); const AliasAttr *AA = D->getAttr(); StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); auto *Alias = cast(Entry); const llvm::GlobalValue *GV = getAliasedGlobal(*Alias); if (!GV) { Error = true; Diags.Report(AA->getLocation(), diag::err_cyclic_alias); } else if (GV->isDeclaration()) { Error = true; Diags.Report(AA->getLocation(), diag::err_alias_to_undefined); } llvm::Constant *Aliasee = Alias->getAliasee(); llvm::GlobalValue *AliaseeGV; if (auto CE = dyn_cast(Aliasee)) AliaseeGV = cast(CE->getOperand(0)); else AliaseeGV = cast(Aliasee); if (const SectionAttr *SA = D->getAttr()) { StringRef AliasSection = SA->getName(); if (AliasSection != AliaseeGV->getSection()) Diags.Report(SA->getLocation(), diag::warn_alias_with_section) << AliasSection; } // We have to handle alias to weak aliases in here. LLVM itself disallows // this since the object semantics would not match the IL one. For // compatibility with gcc we implement it by just pointing the alias // to its aliasee's aliasee. We also warn, since the user is probably // expecting the link to be weak. if (auto GA = dyn_cast(AliaseeGV)) { if (GA->mayBeOverridden()) { Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias) << GV->getName() << GA->getName(); Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( GA->getAliasee(), Alias->getType()); Alias->setAliasee(Aliasee); } } } if (!Error) return; for (std::vector::iterator I = Aliases.begin(), E = Aliases.end(); I != E; ++I) { const GlobalDecl &GD = *I; StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); auto *Alias = cast(Entry); Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType())); Alias->eraseFromParent(); } } void CodeGenModule::clear() { DeferredDeclsToEmit.clear(); } void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile) { if (!hasDiagnostics()) return; if (VisitedInMainFile > 0 && VisitedInMainFile == MissingInMainFile) { if (MainFile.empty()) MainFile = ""; Diags.Report(diag::warn_profile_data_unprofiled) << MainFile; } else Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing << Mismatched; } void CodeGenModule::Release() { EmitDeferred(); applyReplacements(); checkAliases(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); EmitCXXThreadLocalInitFunc(); if (ObjCRuntime) if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); if (PGOReader && PGOStats.hasDiagnostics()) PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); EmitStaticExternCAliases(); EmitDeferredUnusedCoverageMappings(); if (CoverageMapping) CoverageMapping->emit(); emitLLVMUsed(); if (CodeGenOpts.Autolink && (Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) { EmitModuleLinkOptions(); } if (CodeGenOpts.DwarfVersion) // We actually want the latest version when there are conflicts. // We can change from Warning to Latest if such mode is supported. getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version", CodeGenOpts.DwarfVersion); if (DebugInfo) // We support a single version in the linked module. The LLVM // parser will drop debug info with a different version number // (and warn about it, too). getModule().addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION); // We need to record the widths of enums and wchar_t, so that we can generate // the correct build attributes in the ARM backend. llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); if ( Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) { // Width of wchar_t in bytes uint64_t WCharWidth = Context.getTypeSizeInChars(Context.getWideCharType()).getQuantity(); getModule().addModuleFlag(llvm::Module::Error, "wchar_size", WCharWidth); // The minimum width of an enum in bytes uint64_t EnumWidth = Context.getLangOpts().ShortEnums ? 1 : 4; getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth); } if (uint32_t PLevel = Context.getLangOpts().PICLevel) { llvm::PICLevel::Level PL = llvm::PICLevel::Default; switch (PLevel) { case 0: break; case 1: PL = llvm::PICLevel::Small; break; case 2: PL = llvm::PICLevel::Large; break; default: llvm_unreachable("Invalid PIC Level"); } getModule().setPICLevel(PL); } SimplifyPersonality(); if (getCodeGenOpts().EmitDeclMetadata) EmitDeclMetadata(); if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes) EmitCoverageFile(); if (DebugInfo) DebugInfo->finalize(); EmitVersionIdentMetadata(); EmitTargetMetadata(); } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. Types.UpdateCompletedType(TD); } llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) { if (!TBAA) return nullptr; return TBAA->getTBAAInfo(QTy); } llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() { if (!TBAA) return nullptr; return TBAA->getTBAAInfoForVTablePtr(); } llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { if (!TBAA) return nullptr; return TBAA->getTBAAStructInfo(QTy); } llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) { if (!TBAA) return nullptr; return TBAA->getTBAAStructTypeInfo(QTy); } llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN, uint64_t O) { if (!TBAA) return nullptr; return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O); } /// Decorate the instruction with a TBAA tag. For both scalar TBAA /// and struct-path aware TBAA, the tag has the same format: /// base type, access type and offset. /// When ConvertTypeToTag is true, we create a tag based on the scalar type. void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo, bool ConvertTypeToTag) { if (ConvertTypeToTag && TBAA) Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAA->getTBAAScalarTagInfo(TBAAInfo)); else Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); } void CodeGenModule::Error(SourceLocation loc, StringRef message) { unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "%0"); getDiags().Report(Context.getFullLoc(loc), diagID) << message; } /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. void CodeGenModule::ErrorUnsupported(const Stmt *S, const char *Type) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(S->getLocStart()), DiagID) << Msg << S->getSourceRange(); } /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified decl yet. void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot compile this %0 yet"); std::string Msg = Type; getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { return llvm::ConstantInt::get(SizeTy, size.getQuantity()); } void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const { // Internal definitions always have default visibility. if (GV->hasLocalLinkage()) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); return; } // Set visibility for definitions. LinkageInfo LV = D->getLinkageAndVisibility(); if (LV.isVisibilityExplicit() || !GV->hasAvailableExternallyLinkage()) GV->setVisibility(GetLLVMVisibility(LV.getVisibility())); } static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(StringRef S) { return llvm::StringSwitch(S) .Case("global-dynamic", llvm::GlobalVariable::GeneralDynamicTLSModel) .Case("local-dynamic", llvm::GlobalVariable::LocalDynamicTLSModel) .Case("initial-exec", llvm::GlobalVariable::InitialExecTLSModel) .Case("local-exec", llvm::GlobalVariable::LocalExecTLSModel); } static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel( CodeGenOptions::TLSModel M) { switch (M) { case CodeGenOptions::GeneralDynamicTLSModel: return llvm::GlobalVariable::GeneralDynamicTLSModel; case CodeGenOptions::LocalDynamicTLSModel: return llvm::GlobalVariable::LocalDynamicTLSModel; case CodeGenOptions::InitialExecTLSModel: return llvm::GlobalVariable::InitialExecTLSModel; case CodeGenOptions::LocalExecTLSModel: return llvm::GlobalVariable::LocalExecTLSModel; } llvm_unreachable("Invalid TLS model!"); } void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const { assert(D.getTLSKind() && "setting TLS mode on non-TLS var!"); llvm::GlobalValue::ThreadLocalMode TLM; TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel()); // Override the TLS model if it is explicitly specified. if (const TLSModelAttr *Attr = D.getAttr()) { TLM = GetLLVMTLSModel(Attr->getModel()); } GV->setThreadLocalMode(TLM); } StringRef CodeGenModule::getMangledName(GlobalDecl GD) { StringRef &FoundStr = MangledDeclNames[GD.getCanonicalDecl()]; if (!FoundStr.empty()) return FoundStr; const auto *ND = cast(GD.getDecl()); SmallString<256> Buffer; StringRef Str; if (getCXXABI().getMangleContext().shouldMangleDeclName(ND)) { llvm::raw_svector_ostream Out(Buffer); if (const auto *D = dyn_cast(ND)) getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Out); else if (const auto *D = dyn_cast(ND)) getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out); else getCXXABI().getMangleContext().mangleName(ND, Out); Str = Out.str(); } else { IdentifierInfo *II = ND->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); Str = II->getName(); } // Keep the first result in the case of a mangling collision. auto Result = Manglings.insert(std::make_pair(Str, GD)); return FoundStr = Result.first->first(); } StringRef CodeGenModule::getBlockMangledName(GlobalDecl GD, const BlockDecl *BD) { MangleContext &MangleCtx = getCXXABI().getMangleContext(); const Decl *D = GD.getDecl(); SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); if (!D) MangleCtx.mangleGlobalBlock(BD, dyn_cast_or_null(initializedGlobalDecl.getDecl()), Out); else if (const auto *CD = dyn_cast(D)) MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out); else if (const auto *DD = dyn_cast(D)) MangleCtx.mangleDtorBlock(DD, GD.getDtorType(), BD, Out); else MangleCtx.mangleBlock(cast(D), BD, Out); auto Result = Manglings.insert(std::make_pair(Out.str(), BD)); return Result.first->first(); } llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) { return getModule().getNamedValue(Name); } /// AddGlobalCtor - Add a function to the list that will be called before /// main() runs. void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority, llvm::Constant *AssociatedData) { // FIXME: Type coercion of void()* types. GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData)); } /// AddGlobalDtor - Add a function to the list that will be called /// when the module is unloaded. void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority) { // FIXME: Type coercion of void()* types. GlobalDtors.push_back(Structor(Priority, Dtor, nullptr)); } void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) { // Ctor function type is void()*. llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false); llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy); // Get the type of a ctor entry, { i32, void ()*, i8* }. llvm::StructType *CtorStructTy = llvm::StructType::get( Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, nullptr); // Construct the constructor and destructor arrays. SmallVector Ctors; for (CtorList::const_iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { llvm::Constant *S[] = { llvm::ConstantInt::get(Int32Ty, I->Priority, false), llvm::ConstantExpr::getBitCast(I->Initializer, CtorPFTy), (I->AssociatedData ? llvm::ConstantExpr::getBitCast(I->AssociatedData, VoidPtrTy) : llvm::Constant::getNullValue(VoidPtrTy)) }; Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S)); } if (!Ctors.empty()) { llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size()); new llvm::GlobalVariable(TheModule, AT, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(AT, Ctors), GlobalName); } } llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(GlobalDecl GD) { const auto *D = cast(GD.getDecl()); GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (isa(D) && getCXXABI().useThunkForDtorVariant(cast(D), GD.getDtorType())) { // Destructor variants in the Microsoft C++ ABI are always internal or // linkonce_odr thunks emitted on an as-needed basis. return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage : llvm::GlobalValue::LinkOnceODRLinkage; } return getLLVMLinkageForDeclarator(D, Linkage, /*isConstantVariable=*/false); } void CodeGenModule::setFunctionDefinitionAttributes(const FunctionDecl *D, llvm::Function *F) { setNonAliasAttributes(D, F); } void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, const CGFunctionInfo &Info, llvm::Function *F) { unsigned CallingConv; AttributeListType AttributeList; ConstructAttributeList(Info, D, AttributeList, CallingConv, false); F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList)); F->setCallingConv(static_cast(CallingConv)); } /// Determines whether the language options require us to model /// unwind exceptions. We treat -fexceptions as mandating this /// except under the fragile ObjC ABI with only ObjC exceptions /// enabled. This means, for example, that C with -fexceptions /// enables this. static bool hasUnwindExceptions(const LangOptions &LangOpts) { // If exceptions are completely disabled, obviously this is false. if (!LangOpts.Exceptions) return false; // If C++ exceptions are enabled, this is true. if (LangOpts.CXXExceptions) return true; // If ObjC exceptions are enabled, this depends on the ABI. if (LangOpts.ObjCExceptions) { return LangOpts.ObjCRuntime.hasUnwindExceptions(); } return true; } void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F) { llvm::AttrBuilder B; if (CodeGenOpts.UnwindTables) B.addAttribute(llvm::Attribute::UWTable); if (!hasUnwindExceptions(LangOpts)) B.addAttribute(llvm::Attribute::NoUnwind); if (D->hasAttr()) { // Naked implies noinline: we should not be inlining such functions. B.addAttribute(llvm::Attribute::Naked); B.addAttribute(llvm::Attribute::NoInline); } else if (D->hasAttr()) { B.addAttribute(llvm::Attribute::NoDuplicate); } else if (D->hasAttr()) { B.addAttribute(llvm::Attribute::NoInline); } else if (D->hasAttr() && !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoInline)) { // (noinline wins over always_inline, and we can't specify both in IR) B.addAttribute(llvm::Attribute::AlwaysInline); } if (D->hasAttr()) { if (!D->hasAttr()) B.addAttribute(llvm::Attribute::OptimizeForSize); B.addAttribute(llvm::Attribute::Cold); } if (D->hasAttr()) B.addAttribute(llvm::Attribute::MinSize); if (LangOpts.getStackProtector() == LangOptions::SSPOn) B.addAttribute(llvm::Attribute::StackProtect); else if (LangOpts.getStackProtector() == LangOptions::SSPStrong) B.addAttribute(llvm::Attribute::StackProtectStrong); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) B.addAttribute(llvm::Attribute::StackProtectReq); // Add sanitizer attributes if function is not blacklisted. if (!isInSanitizerBlacklist(F, D->getLocation())) { // When AddressSanitizer is enabled, set SanitizeAddress attribute // unless __attribute__((no_sanitize_address)) is used. if (LangOpts.Sanitize.has(SanitizerKind::Address) && !D->hasAttr()) B.addAttribute(llvm::Attribute::SanitizeAddress); // Same for ThreadSanitizer and __attribute__((no_sanitize_thread)) if (LangOpts.Sanitize.has(SanitizerKind::Thread) && !D->hasAttr()) B.addAttribute(llvm::Attribute::SanitizeThread); // Same for MemorySanitizer and __attribute__((no_sanitize_memory)) if (LangOpts.Sanitize.has(SanitizerKind::Memory) && !D->hasAttr()) B.addAttribute(llvm::Attribute::SanitizeMemory); } F->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get( F->getContext(), llvm::AttributeSet::FunctionIndex, B)); if (D->hasAttr()) { // OptimizeNone implies noinline; we should not be inlining such functions. F->addFnAttr(llvm::Attribute::OptimizeNone); F->addFnAttr(llvm::Attribute::NoInline); // OptimizeNone wins over OptimizeForSize, MinSize, AlwaysInline. assert(!F->hasFnAttribute(llvm::Attribute::OptimizeForSize) && "OptimizeNone and OptimizeForSize on same function!"); assert(!F->hasFnAttribute(llvm::Attribute::MinSize) && "OptimizeNone and MinSize on same function!"); assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) && "OptimizeNone and AlwaysInline on same function!"); // Attribute 'inlinehint' has no effect on 'optnone' functions. // Explicitly remove it from the set of function attributes. F->removeFnAttr(llvm::Attribute::InlineHint); } if (isa(D) || isa(D)) F->setUnnamedAddr(true); else if (const auto *MD = dyn_cast(D)) if (MD->isVirtual()) F->setUnnamedAddr(true); unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); if (alignment) F->setAlignment(alignment); // C++ ABI requires 2-byte alignment for member functions. if (F->getAlignment() < 2 && isa(D)) F->setAlignment(2); } void CodeGenModule::SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV) { if (const auto *ND = dyn_cast(D)) setGlobalVisibility(GV, ND); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); if (D->hasAttr()) addUsedGlobal(GV); } void CodeGenModule::setAliasAttributes(const Decl *D, llvm::GlobalValue *GV) { SetCommonAttributes(D, GV); // Process the dllexport attribute based on whether the original definition // (not necessarily the aliasee) was exported. if (D->hasAttr()) GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); } void CodeGenModule::setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO) { SetCommonAttributes(D, GO); if (const SectionAttr *SA = D->getAttr()) GO->setSection(SA->getName()); getTargetCodeGenInfo().SetTargetAttributes(D, GO, *this); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, llvm::Function *F, const CGFunctionInfo &FI) { SetLLVMFunctionAttributes(D, FI, F); SetLLVMFunctionAttributesForDefinition(D, F); F->setLinkage(llvm::Function::InternalLinkage); setNonAliasAttributes(D, F); } static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, const NamedDecl *ND) { // Set linkage and visibility in case we never see a definition. LinkageInfo LV = ND->getLinkageAndVisibility(); if (LV.getLinkage() != ExternalLinkage) { // Don't set internal linkage on declarations. } else { if (ND->hasAttr()) { GV->setLinkage(llvm::GlobalValue::ExternalLinkage); GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); } else if (ND->hasAttr()) { GV->setLinkage(llvm::GlobalValue::ExternalLinkage); GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); } else if (ND->hasAttr() || ND->isWeakImported()) { // "extern_weak" is overloaded in LLVM; we probably should have // separate linkage types for this. GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } // Set visibility on a declaration only if it's explicit. if (LV.isVisibilityExplicit()) GV->setVisibility(CodeGenModule::GetLLVMVisibility(LV.getVisibility())); } } void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, bool IsThunk) { if (unsigned IID = F->getIntrinsicID()) { // If this is an intrinsic function, set the function's attributes // to the intrinsic's attributes. F->setAttributes(llvm::Intrinsic::getAttributes(getLLVMContext(), (llvm::Intrinsic::ID)IID)); return; } const auto *FD = cast(GD.getDecl()); if (!IsIncompleteFunction) SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F); // Add the Returned attribute for "this", except for iOS 5 and earlier // where substantial code, including the libstdc++ dylib, was compiled with // GCC and does not actually return "this". if (!IsThunk && getCXXABI().HasThisReturn(GD) && !(getTarget().getTriple().isiOS() && getTarget().getTriple().isOSVersionLT(6))) { assert(!F->arg_empty() && F->arg_begin()->getType() ->canLosslesslyBitCastTo(F->getReturnType()) && "unexpected this return"); F->addAttribute(1, llvm::Attribute::Returned); } // Only a few attributes are set on declarations; these may later be // overridden by a definition. setLinkageAndVisibilityForGV(F, FD); if (const auto *Dtor = dyn_cast_or_null(FD)) { if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) { // Don't dllexport/import destructor thunks. F->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); } } if (const SectionAttr *SA = FD->getAttr()) F->setSection(SA->getName()); // A replaceable global allocation function does not act like a builtin by // default, only if it is invoked by a new-expression or delete-expression. if (FD->isReplaceableGlobalAllocationFunction()) F->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoBuiltin); } void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) { assert(!GV->isDeclaration() && "Only globals with definition can force usage."); LLVMUsed.push_back(GV); } void CodeGenModule::addCompilerUsedGlobal(llvm::GlobalValue *GV) { assert(!GV->isDeclaration() && "Only globals with definition can force usage."); LLVMCompilerUsed.push_back(GV); } static void emitUsed(CodeGenModule &CGM, StringRef Name, std::vector &List) { // Don't create llvm.used if there is no need. if (List.empty()) return; // Convert List to what ConstantArray needs. SmallVector UsedArray; UsedArray.resize(List.size()); for (unsigned i = 0, e = List.size(); i != e; ++i) { UsedArray[i] = - llvm::ConstantExpr::getBitCast(cast(&*List[i]), - CGM.Int8PtrTy); + llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( + cast(&*List[i]), CGM.Int8PtrTy); } if (UsedArray.empty()) return; llvm::ArrayType *ATy = llvm::ArrayType::get(CGM.Int8PtrTy, UsedArray.size()); auto *GV = new llvm::GlobalVariable( CGM.getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage, llvm::ConstantArray::get(ATy, UsedArray), Name); GV->setSection("llvm.metadata"); } void CodeGenModule::emitLLVMUsed() { emitUsed(*this, "llvm.used", LLVMUsed); emitUsed(*this, "llvm.compiler.used", LLVMCompilerUsed); } void CodeGenModule::AppendLinkerOptions(StringRef Opts) { auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opts); LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) { llvm::SmallString<32> Opt; getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt); auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt); LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } void CodeGenModule::AddDependentLib(StringRef Lib) { llvm::SmallString<24> Opt; getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt); auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt); LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } /// \brief Add link options implied by the given module, including modules /// it depends on, using a postorder walk. static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, SmallVectorImpl &Metadata, llvm::SmallPtrSet &Visited) { // Import this module's parent. if (Mod->Parent && Visited.insert(Mod->Parent).second) { addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited); } // Import this module's dependencies. for (unsigned I = Mod->Imports.size(); I > 0; --I) { if (Visited.insert(Mod->Imports[I - 1]).second) addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited); } // Add linker options to link against the libraries/frameworks // described by this module. llvm::LLVMContext &Context = CGM.getLLVMContext(); for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) { // Link against a framework. Frameworks are currently Darwin only, so we // don't to ask TargetCodeGenInfo for the spelling of the linker option. if (Mod->LinkLibraries[I-1].IsFramework) { llvm::Metadata *Args[2] = { llvm::MDString::get(Context, "-framework"), llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library)}; Metadata.push_back(llvm::MDNode::get(Context, Args)); continue; } // Link against a library. llvm::SmallString<24> Opt; CGM.getTargetCodeGenInfo().getDependentLibraryOption( Mod->LinkLibraries[I-1].Library, Opt); auto *OptString = llvm::MDString::get(Context, Opt); Metadata.push_back(llvm::MDNode::get(Context, OptString)); } } void CodeGenModule::EmitModuleLinkOptions() { // Collect the set of all of the modules we want to visit to emit link // options, which is essentially the imported modules and all of their // non-explicit child modules. llvm::SetVector LinkModules; llvm::SmallPtrSet Visited; SmallVector Stack; // Seed the stack with imported modules. for (llvm::SetVector::iterator M = ImportedModules.begin(), MEnd = ImportedModules.end(); M != MEnd; ++M) { if (Visited.insert(*M).second) Stack.push_back(*M); } // Find all of the modules to import, making a little effort to prune // non-leaf modules. while (!Stack.empty()) { clang::Module *Mod = Stack.pop_back_val(); bool AnyChildren = false; // Visit the submodules of this module. for (clang::Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) { // Skip explicit children; they need to be explicitly imported to be // linked against. if ((*Sub)->IsExplicit) continue; if (Visited.insert(*Sub).second) { Stack.push_back(*Sub); AnyChildren = true; } } // We didn't find any children, so add this module to the list of // modules to link against. if (!AnyChildren) { LinkModules.insert(Mod); } } // Add link options for all of the imported modules in reverse topological // order. We don't do anything to try to order import link flags with respect // to linker options inserted by things like #pragma comment(). SmallVector MetadataArgs; Visited.clear(); for (llvm::SetVector::iterator M = LinkModules.begin(), MEnd = LinkModules.end(); M != MEnd; ++M) { if (Visited.insert(*M).second) addLinkOptionsPostorder(*this, *M, MetadataArgs, Visited); } std::reverse(MetadataArgs.begin(), MetadataArgs.end()); LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end()); // Add the linker options metadata flag. getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options", llvm::MDNode::get(getLLVMContext(), LinkerOptionsMetadata)); } void CodeGenModule::EmitDeferred() { // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. while (true) { if (!DeferredVTables.empty()) { EmitDeferredVTables(); // Emitting a v-table doesn't directly cause more v-tables to // become deferred, although it can cause functions to be // emitted that then need those v-tables. assert(DeferredVTables.empty()); } // Stop if we're out of both deferred v-tables and deferred declarations. if (DeferredDeclsToEmit.empty()) break; DeferredGlobal &G = DeferredDeclsToEmit.back(); GlobalDecl D = G.GD; llvm::GlobalValue *GV = G.GV; DeferredDeclsToEmit.pop_back(); assert(!GV || GV == GetGlobalValue(getMangledName(D))); if (!GV) GV = GetGlobalValue(getMangledName(D)); // Check to see if we've already emitted this. This is necessary // for a couple of reasons: first, decls can end up in the // deferred-decls queue multiple times, and second, decls can end // up with definitions in unusual ways (e.g. by an extern inline // function acquiring a strong function redefinition). Just // ignore these cases. if (GV && !GV->isDeclaration()) continue; // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D, GV); } } void CodeGenModule::EmitGlobalAnnotations() { if (Annotations.empty()) return; // Create a new global variable for the ConstantStruct in the Module. llvm::Constant *Array = llvm::ConstantArray::get(llvm::ArrayType::get( Annotations[0]->getType(), Annotations.size()), Annotations); auto *gv = new llvm::GlobalVariable(getModule(), Array->getType(), false, llvm::GlobalValue::AppendingLinkage, Array, "llvm.global.annotations"); gv->setSection(AnnotationSection); } llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) { llvm::Constant *&AStr = AnnotationStrings[Str]; if (AStr) return AStr; // Not found yet, create a new global. llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str); auto *gv = new llvm::GlobalVariable(getModule(), s->getType(), true, llvm::GlobalValue::PrivateLinkage, s, ".str"); gv->setSection(AnnotationSection); gv->setUnnamedAddr(true); AStr = gv; return gv; } llvm::Constant *CodeGenModule::EmitAnnotationUnit(SourceLocation Loc) { SourceManager &SM = getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isValid()) return EmitAnnotationString(PLoc.getFilename()); return EmitAnnotationString(SM.getBufferName(Loc)); } llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) { SourceManager &SM = getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(L); unsigned LineNo = PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L); return llvm::ConstantInt::get(Int32Ty, LineNo); } llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, SourceLocation L) { // Get the globals for file name, annotation, and the line number. llvm::Constant *AnnoGV = EmitAnnotationString(AA->getAnnotation()), *UnitGV = EmitAnnotationUnit(L), *LineNoCst = EmitAnnotationLineNo(L); // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[4] = { llvm::ConstantExpr::getBitCast(GV, Int8PtrTy), llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), LineNoCst }; return llvm::ConstantStruct::getAnon(Fields); } void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV) { assert(D->hasAttr() && "no annotate attribute"); // Get the struct elements for these annotations. for (const auto *I : D->specific_attrs()) Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation())); } bool CodeGenModule::isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const { const auto &SanitizerBL = getContext().getSanitizerBlacklist(); // Blacklist by function name. if (SanitizerBL.isBlacklistedFunction(Fn->getName())) return true; // Blacklist by location. if (!Loc.isInvalid()) return SanitizerBL.isBlacklistedLocation(Loc); // If location is unknown, this may be a compiler-generated function. Assume // it's located in the main file. auto &SM = Context.getSourceManager(); if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { return SanitizerBL.isBlacklistedFile(MainFile->getName()); } return false; } bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, StringRef Category) const { // For now globals can be blacklisted only in ASan. if (!LangOpts.Sanitize.has(SanitizerKind::Address)) return false; const auto &SanitizerBL = getContext().getSanitizerBlacklist(); if (SanitizerBL.isBlacklistedGlobal(GV->getName(), Category)) return true; if (SanitizerBL.isBlacklistedLocation(Loc, Category)) return true; // Check global type. if (!Ty.isNull()) { // Drill down the array types: if global variable of a fixed type is // blacklisted, we also don't instrument arrays of them. while (auto AT = dyn_cast(Ty.getTypePtr())) Ty = AT->getElementType(); Ty = Ty.getCanonicalType().getUnqualifiedType(); // We allow to blacklist only record types (classes, structs etc.) if (Ty->isRecordType()) { std::string TypeStr = Ty.getAsString(getContext().getPrintingPolicy()); if (SanitizerBL.isBlacklistedType(TypeStr, Category)) return true; } } return false; } bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) { // Never defer when EmitAllDecls is specified. if (LangOpts.EmitAllDecls) return true; return getContext().DeclMustBeEmitted(Global); } bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { if (const auto *FD = dyn_cast(Global)) if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) // Implicit template instantiations may change linkage if they are later // explicitly instantiated, so they should not be emitted eagerly. return false; return true; } llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor( const CXXUuidofExpr* E) { // Sema has verified that IIDSource has a __declspec(uuid()), and that its // well-formed. StringRef Uuid = E->getUuidAsStringRef(Context); std::string Name = "_GUID_" + Uuid.lower(); std::replace(Name.begin(), Name.end(), '-', '_'); // Look for an existing global. if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name)) return GV; llvm::Constant *Init = EmitUuidofInitializer(Uuid); assert(Init && "failed to initialize as constant"); auto *GV = new llvm::GlobalVariable( getModule(), Init->getType(), /*isConstant=*/true, llvm::GlobalValue::LinkOnceODRLinkage, Init, Name); return GV; } llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { const AliasAttr *AA = VD->getAttr(); assert(AA && "No alias?"); llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType()); // See if there is already something with the target's name in the module. llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee()); if (Entry) { unsigned AS = getContext().getTargetAddressSpace(VD->getType()); return llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS)); } llvm::Constant *Aliasee; if (isa(DeclTy)) Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(cast(VD)), /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), nullptr); auto *F = cast(Aliasee); F->setLinkage(llvm::Function::ExternalWeakLinkage); WeakRefReferences.insert(F); return Aliasee; } void CodeGenModule::EmitGlobal(GlobalDecl GD) { const auto *Global = cast(GD.getDecl()); // Weak references don't produce any output by themselves. if (Global->hasAttr()) return; // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr()) return EmitAliasDefinition(GD); // If this is CUDA, be selective about which declarations we emit. if (LangOpts.CUDA) { if (CodeGenOpts.CUDAIsDevice) { if (!Global->hasAttr() && !Global->hasAttr() && !Global->hasAttr() && !Global->hasAttr()) return; } else { if (!Global->hasAttr() && ( Global->hasAttr() || Global->hasAttr() || Global->hasAttr())) return; } } // Ignore declarations, they will be emitted on their first use. if (const auto *FD = dyn_cast(Global)) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { if (!FD->doesDeclarationForceExternallyVisibleDefinition()) return; StringRef MangledName = getMangledName(GD); // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::Type *Ty = getTypes().GetFunctionType(FI); GetOrCreateLLVMFunction(MangledName, Ty, GD, /*ForVTable=*/false, /*DontDefer=*/false); return; } } else { const auto *VD = cast(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); if (VD->isThisDeclarationADefinition() != VarDecl::Definition && !Context.isMSStaticDataMemberInlineDefinition(VD)) return; } // Defer code generation to first use when possible, e.g. if this is an inline // function. If the global must always be emitted, do it eagerly if possible // to benefit from cache locality. if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) { // Emit the definition if it can't be deferred. EmitGlobalDefinition(GD); return; } // If we're deferring emission of a C++ variable with an // initializer, remember the order in which it appeared in the file. if (getLangOpts().CPlusPlus && isa(Global) && cast(Global)->hasInit()) { DelayedCXXInitPosition[Global] = CXXGlobalInits.size(); CXXGlobalInits.push_back(nullptr); } StringRef MangledName = getMangledName(GD); if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) { // The value has already been used and should therefore be emitted. addDeferredDeclToEmit(GV, GD); } else if (MustBeEmitted(Global)) { // The value must be emitted, but cannot be emitted eagerly. assert(!MayBeEmittedEagerly(Global)); addDeferredDeclToEmit(/*GV=*/nullptr, GD); } else { // Otherwise, remember that we saw a deferred decl with this name. The // first use of the mangled name will cause it to move into // DeferredDeclsToEmit. DeferredDecls[MangledName] = GD; } } namespace { struct FunctionIsDirectlyRecursive : public RecursiveASTVisitor { const StringRef Name; const Builtin::Context &BI; bool Result; FunctionIsDirectlyRecursive(StringRef N, const Builtin::Context &C) : Name(N), BI(C), Result(false) { } typedef RecursiveASTVisitor Base; bool TraverseCallExpr(CallExpr *E) { const FunctionDecl *FD = E->getDirectCallee(); if (!FD) return true; AsmLabelAttr *Attr = FD->getAttr(); if (Attr && Name == Attr->getLabel()) { Result = true; return false; } unsigned BuiltinID = FD->getBuiltinID(); if (!BuiltinID) return true; StringRef BuiltinName = BI.GetName(BuiltinID); if (BuiltinName.startswith("__builtin_") && Name == BuiltinName.slice(strlen("__builtin_"), StringRef::npos)) { Result = true; return false; } return true; } }; } // isTriviallyRecursive - Check if this function calls another // decl that, because of the asm attribute or the other decl being a builtin, // ends up pointing to itself. bool CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) { StringRef Name; if (getCXXABI().getMangleContext().shouldMangleDeclName(FD)) { // asm labels are a special kind of mangling we have to support. AsmLabelAttr *Attr = FD->getAttr(); if (!Attr) return false; Name = Attr->getLabel(); } else { Name = FD->getName(); } FunctionIsDirectlyRecursive Walker(Name, Context.BuiltinInfo); Walker.TraverseFunctionDecl(const_cast(FD)); return Walker.Result; } bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) { if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage) return true; const auto *F = cast(GD.getDecl()); if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr()) return false; // PR9614. Avoid cases where the source code is lying to us. An available // externally function should have an equivalent function somewhere else, // but a function that calls itself is clearly not equivalent to the real // implementation. // This happens in glibc's btowc and in some configure checks. return !isTriviallyRecursive(F); } /// If the type for the method's class was generated by /// CGDebugInfo::createContextChain(), the cache contains only a /// limited DIType without any declarations. Since EmitFunctionStart() /// needs to find the canonical declaration for each method, we need /// to construct the complete type prior to emitting the method. void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) { if (!D->isInstance()) return; if (CGDebugInfo *DI = getModuleDebugInfo()) if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { const auto *ThisPtr = cast(D->getThisType(getContext())); DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation()); } } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); PrettyStackTraceDecl CrashInfo(const_cast(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); if (isa(D)) { // At -O0, don't generate IR for functions with available_externally // linkage. if (!shouldEmitFunction(GD)) return; if (const auto *Method = dyn_cast(D)) { CompleteDIClassType(Method); // Make sure to emit the definition(s) before we emit the thunks. // This is necessary for the generation of certain thunks. if (const auto *CD = dyn_cast(Method)) ABI->emitCXXStructor(CD, getFromCtorType(GD.getCtorType())); else if (const auto *DD = dyn_cast(Method)) ABI->emitCXXStructor(DD, getFromDtorType(GD.getDtorType())); else EmitGlobalFunctionDefinition(GD, GV); if (Method->isVirtual()) getVTables().EmitThunks(GD); return; } return EmitGlobalFunctionDefinition(GD, GV); } if (const auto *VD = dyn_cast(D)) return EmitGlobalVarDefinition(VD); llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the /// module, create and return an llvm Function with the specified type. If there /// is something in the module with the specified name, return it potentially /// bitcasted to the right type. /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the function when it is first created. llvm::Constant * CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl GD, bool ForVTable, bool DontDefer, bool IsThunk, llvm::AttributeSet ExtraAttrs) { const Decl *D = GD.getDecl(); // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.erase(Entry)) { const FunctionDecl *FD = cast_or_null(D); if (FD && !FD->hasAttr()) Entry->setLinkage(llvm::Function::ExternalLinkage); } // Handle dropped DLL attributes. if (D && !D->hasAttr() && !D->hasAttr()) Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); if (Entry->getType()->getElementType() == Ty) return Entry; // Make sure the result is of the correct type. return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo()); } // This function doesn't have a complete type (for example, the return // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; llvm::FunctionType *FTy; if (isa(Ty)) { FTy = cast(Ty); } else { FTy = llvm::FunctionType::get(VoidTy, false); IsIncompleteFunction = true; } llvm::Function *F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, MangledName, &getModule()); assert(F->getName() == MangledName && "name was uniqued!"); if (D) SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) { llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex); F->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(VMContext, llvm::AttributeSet::FunctionIndex, B)); } if (!DontDefer) { // All MSVC dtors other than the base dtor are linkonce_odr and delegate to // each other bottoming out with the base dtor. Therefore we emit non-base // dtors on usage, even if there is no dtor definition in the TU. if (D && isa(D) && getCXXABI().useThunkForDtorVariant(cast(D), GD.getDtorType())) addDeferredDeclToEmit(F, GD); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. auto DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the // DeferredDeclsToEmit list, and remove it from DeferredDecls (since we // don't need it anymore). addDeferredDeclToEmit(F, DDI->second); DeferredDecls.erase(DDI); // Otherwise, if this is a sized deallocation function, emit a weak // definition // for it at the end of the translation unit. } else if (D && cast(D) ->getCorrespondingUnsizedGlobalDeallocationFunction()) { addDeferredDeclToEmit(F, GD); // Otherwise, there are cases we have to worry about where we're // using a declaration for which we must emit a definition but where // we might not find a top-level definition: // - member functions defined inline in their classes // - friend functions defined inline in some class // - special member functions with implicit definitions // If we ever change our AST traversal to walk into class methods, // this will be unnecessary. // // We also don't emit a definition for a function if it's going to be an // entry in a vtable, unless it's already marked as used. } else if (getLangOpts().CPlusPlus && D) { // Look for a declaration that's lexically in a record. for (const auto *FD = cast(D)->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) { if (isa(FD->getLexicalDeclContext())) { if (FD->doesThisDeclarationHaveABody()) { addDeferredDeclToEmit(F, GD.getWithDecl(FD)); break; } } } } } // Make sure the result is of the requested type. if (!IsIncompleteFunction) { assert(F->getType()->getElementType() == Ty); return F; } llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); return llvm::ConstantExpr::getBitCast(F, PTy); } /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it (this occurs when we see a definition of the function). llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty, bool ForVTable, bool DontDefer) { // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast(GD.getDecl())->getType()); StringRef MangledName = getMangledName(GD); return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer); } /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant * CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, llvm::AttributeSet ExtraAttrs) { llvm::Constant *C = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs); if (auto *F = dyn_cast(C)) if (F->empty()) F->setCallingConv(getRuntimeCC()); return C; } /// CreateBuiltinFunction - Create a new builtin function with the specified /// type and name. llvm::Constant * CodeGenModule::CreateBuiltinFunction(llvm::FunctionType *FTy, StringRef Name, llvm::AttributeSet ExtraAttrs) { llvm::Constant *C = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, /*DontDefer=*/false, /*IsThunk=*/false, ExtraAttrs); if (auto *F = dyn_cast(C)) if (F->empty()) F->setCallingConv(getBuiltinCC()); return C; } /// isTypeConstant - Determine whether an object of this type can be emitted /// as a constant. /// /// If ExcludeCtor is true, the duration when the object's constructor runs /// will not be considered. The caller will need to verify that the object is /// not written to during its construction. bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) { if (!Ty.isConstant(Context) && !Ty->isReferenceType()) return false; if (Context.getLangOpts().CPlusPlus) { if (const CXXRecordDecl *Record = Context.getBaseElementType(Ty)->getAsCXXRecordDecl()) return ExcludeCtor && !Record->hasMutableFields() && Record->hasTrivialDestructor(); } return true; } /// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module, /// create and return an llvm GlobalVariable with the specified type. If there /// is something in the module with the specified name, return it potentially /// bitcasted to the right type. /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the global when it is first created. llvm::Constant * CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *Ty, const VarDecl *D) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.erase(Entry)) { if (D && !D->hasAttr()) Entry->setLinkage(llvm::Function::ExternalLinkage); } // Handle dropped DLL attributes. if (D && !D->hasAttr() && !D->hasAttr()) Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); if (Entry->getType() == Ty) return Entry; // Make sure the result is of the correct type. if (Entry->getType()->getAddressSpace() != Ty->getAddressSpace()) return llvm::ConstantExpr::getAddrSpaceCast(Entry, Ty); return llvm::ConstantExpr::getBitCast(Entry, Ty); } unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace()); auto *GV = new llvm::GlobalVariable( getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. auto DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). addDeferredDeclToEmit(GV, DDI->second); DeferredDecls.erase(DDI); } // Handle things which are present even on external declarations. if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. GV->setConstant(isTypeConstant(D->getType(), false)); setLinkageAndVisibilityForGV(GV, D); if (D->getTLSKind()) { if (D->getTLSKind() == VarDecl::TLS_Dynamic) CXXThreadLocals.push_back(std::make_pair(D, GV)); setTLSMode(GV, *D); } // If required by the ABI, treat declarations of static data members with // inline initializers as definitions. if (getContext().isMSStaticDataMemberInlineDefinition(D)) { EmitGlobalVarDefinition(D); } // Handle XCore specific ABI requirements. if (getTarget().getTriple().getArch() == llvm::Triple::xcore && D->getLanguageLinkage() == CLanguageLinkage && D->getType().isConstant(Context) && isExternallyVisible(D->getLinkageAndVisibility().getLinkage())) GV->setSection(".cp.rodata"); } if (AddrSpace != Ty->getAddressSpace()) return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty); return GV; } llvm::GlobalVariable * CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage) { llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name); llvm::GlobalVariable *OldGV = nullptr; if (GV) { // Check if the variable has the right type. if (GV->getType()->getElementType() == Ty) return GV; // Because C++ name mangling, the only way we can end up with an already // existing global with the same name is if it has been declared extern "C". assert(GV->isDeclaration() && "Declaration has wrong type!"); OldGV = GV; } // Create a new variable. GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name); if (OldGV) { // Replace occurrences of the old variable if needed. GV->takeName(OldGV); if (!OldGV->use_empty()) { llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); OldGV->replaceAllUsesWith(NewPtrForOldDecl); } OldGV->eraseFromParent(); } return GV; } /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be created with the specified type instead of whatever the /// normal requested type would be. llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty) { assert(D->hasGlobalStorage() && "Not a global variable"); QualType ASTTy = D->getType(); if (!Ty) Ty = getTypes().ConvertTypeForMem(ASTTy); llvm::PointerType *PTy = llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); StringRef MangledName = getMangledName(D); return GetOrCreateLLVMGlobal(MangledName, PTy, D); } /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant * CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty, StringRef Name) { return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), nullptr); } void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { assert(!D->getInit() && "Cannot emit definite definitions here!"); if (!MustBeEmitted(D)) { // If we have not seen a reference to this variable yet, place it // into the deferred declarations table to be emitted if needed // later. StringRef MangledName = getMangledName(D); if (!GetGlobalValue(MangledName)) { DeferredDecls[MangledName] = D; return; } } // The tentative definition is the only definition. EmitGlobalVarDefinition(D); } CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( TheDataLayout.getTypeStoreSizeInBits(Ty)); } unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace) { if (LangOpts.CUDA && CodeGenOpts.CUDAIsDevice) { if (D->hasAttr()) AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant); else if (D->hasAttr()) AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared); else AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device); } return AddrSpace; } template void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV) { if (!getLangOpts().CPlusPlus) return; // Must have 'used' attribute, or else inline assembly can't rely on // the name existing. if (!D->template hasAttr()) return; // Must have internal linkage and an ordinary name. if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage) return; // Must be in an extern "C" context. Entities declared directly within // a record are not extern "C" even if the record is in such a context. const SomeDecl *First = D->getFirstDecl(); if (First->getDeclContext()->isRecord() || !First->isInExternCContext()) return; // OK, this is an internal linkage entity inside an extern "C" linkage // specification. Make a note of that so we can give it the "expected" // mangled name if nothing else is using that name. std::pair R = StaticExternCValues.insert(std::make_pair(D->getIdentifier(), GV)); // If we have multiple internal linkage entities with the same name // in extern "C" regions, none of them gets that name. if (!R.second) R.first->second = nullptr; } void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = nullptr; QualType ASTTy = D->getType(); CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); bool NeedsGlobalCtor = false; bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor(); const VarDecl *InitDecl; const Expr *InitExpr = D->getAnyInitializer(InitDecl); if (!InitExpr) { // This is a tentative definition; tentative definitions are // implicitly initialized with { 0 }. // // Note that tentative definitions are only emitted at the end of // a translation unit, so they should never have incomplete // type. In addition, EmitTentativeDefinition makes sure that we // never attempt to emit a tentative definition if a real one // exists. A use may still exists, however, so we still may need // to do a RAUW. assert(!ASTTy->isIncompleteType() && "Unexpected incomplete type"); Init = EmitNullConstant(D->getType()); } else { initializedGlobalDecl = GlobalDecl(D); Init = EmitConstantInit(*InitDecl); if (!Init) { QualType T = InitExpr->getType(); if (D->getType()->isReferenceType()) T = D->getType(); if (getLangOpts().CPlusPlus) { Init = EmitNullConstant(T); NeedsGlobalCtor = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); } } else { // We don't need an initializer, so remove the entry for the delayed // initializer position (just in case this entry was delayed) if we // also don't need to register a destructor. if (getLangOpts().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); } } llvm::Type* InitType = Init->getType(); llvm::Constant *Entry = GetAddrOfGlobalVar(D, InitType); // Strip off a bitcast if we got one back. if (auto *CE = dyn_cast(Entry)) { assert(CE->getOpcode() == llvm::Instruction::BitCast || CE->getOpcode() == llvm::Instruction::AddrSpaceCast || // All zero index gep. CE->getOpcode() == llvm::Instruction::GetElementPtr); Entry = CE->getOperand(0); } // Entry is now either a Function or GlobalVariable. auto *GV = dyn_cast(Entry); // We have a definition after a declaration with the wrong type. // We must make a new GlobalVariable* and update everything that used OldGV // (a declaration or tentative definition) with the new GlobalVariable* // (which will be a definition). // // This happens if there is a prototype for a global (e.g. // "extern int x[];") and then a definition of a different type (e.g. // "int x[10];"). This also happens when an initializer has a different type // from the type of the global (this happens with unions). if (!GV || GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) { // Move the old entry aside so that we'll create a new one. Entry->setName(StringRef()); // Make a new global with the correct type, this is now guaranteed to work. GV = cast(GetAddrOfGlobalVar(D, InitType)); // Replace all uses of the old global with the new global llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(GV, Entry->getType()); Entry->replaceAllUsesWith(NewPtrForOldDecl); // Erase the old global, since it is no longer used. cast(Entry)->eraseFromParent(); } MaybeHandleStaticInExternC(D, GV); if (D->hasAttr()) AddGlobalAnnotations(D, GV); GV->setInitializer(Init); // If it is safe to mark the global 'constant', do so now. GV->setConstant(!NeedsGlobalCtor && !NeedsGlobalDtor && isTypeConstant(D->getType(), true)); // If it is in a read-only section, mark it 'constant'. if (const SectionAttr *SA = D->getAttr()) { const ASTContext::SectionInfo &SI = Context.SectionInfos[SA->getName()]; if ((SI.SectionFlags & ASTContext::PSF_Write) == 0) GV->setConstant(true); } GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); // Set the llvm linkage type as appropriate. llvm::GlobalValue::LinkageTypes Linkage = getLLVMLinkageVarDefinition(D, GV->isConstant()); // On Darwin, the backing variable for a C++11 thread_local variable always // has internal linkage; all accesses should just be calls to the // Itanium-specified entry point, which has the normal linkage of the // variable. if (!D->isStaticLocal() && D->getTLSKind() == VarDecl::TLS_Dynamic && Context.getTargetInfo().getTriple().isMacOSX()) Linkage = llvm::GlobalValue::InternalLinkage; GV->setLinkage(Linkage); if (D->hasAttr()) GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); else if (D->hasAttr()) GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); else GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); if (Linkage == llvm::GlobalVariable::CommonLinkage) // common vars aren't constant even if declared const. GV->setConstant(false); setNonAliasAttributes(D, GV); if (D->getTLSKind() && !GV->isThreadLocal()) { if (D->getTLSKind() == VarDecl::TLS_Dynamic) CXXThreadLocals.push_back(std::make_pair(D, GV)); setTLSMode(GV, *D); } // Emit the initializer function if necessary. if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) DI->EmitGlobalVariable(GV, D); } static bool isVarDeclStrongDefinition(const ASTContext &Context, const VarDecl *D, bool NoCommon) { // Don't give variables common linkage if -fno-common was specified unless it // was overridden by a NoCommon attribute. if ((NoCommon || D->hasAttr()) && !D->hasAttr()) return true; // C11 6.9.2/2: // A declaration of an identifier for an object that has file scope without // an initializer, and without a storage-class specifier or with the // storage-class specifier static, constitutes a tentative definition. if (D->getInit() || D->hasExternalStorage()) return true; // A variable cannot be both common and exist in a section. if (D->hasAttr()) return true; // Thread local vars aren't considered common linkage. if (D->getTLSKind()) return true; // Tentative definitions marked with WeakImportAttr are true definitions. if (D->hasAttr()) return true; // Declarations with a required alignment do not have common linakge in MSVC // mode. if (Context.getLangOpts().MSVCCompat && (Context.isAlignmentRequired(D->getType()) || D->hasAttr())) return true; return false; } llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator( const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable) { if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; if (D->hasAttr()) { if (IsConstantVariable) return llvm::GlobalVariable::WeakODRLinkage; else return llvm::GlobalVariable::WeakAnyLinkage; } // We are guaranteed to have a strong definition somewhere else, // so we can use available_externally linkage. if (Linkage == GVA_AvailableExternally) return llvm::Function::AvailableExternallyLinkage; // Note that Apple's kernel linker doesn't support symbol // coalescing, so we need to avoid linkonce and weak linkages there. // Normally, this means we just map to internal, but for explicit // instantiations we'll map to external. // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because // a) if all references in this translation unit are optimized away, we // don't need to codegen it. b) if the function persists, it needs to be // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. if (Linkage == GVA_DiscardableODR) return !Context.getLangOpts().AppleKext ? llvm::Function::LinkOnceODRLinkage : llvm::Function::InternalLinkage; // An explicit instantiation of a template has weak linkage, since // explicit instantiations can occur in multiple translation units // and must all be equivalent. However, we are not allowed to // throw away these explicit instantiations. if (Linkage == GVA_StrongODR) return !Context.getLangOpts().AppleKext ? llvm::Function::WeakODRLinkage : llvm::Function::ExternalLinkage; // C++ doesn't have tentative definitions and thus cannot have common // linkage. if (!getLangOpts().CPlusPlus && isa(D) && !isVarDeclStrongDefinition(Context, cast(D), CodeGenOpts.NoCommon)) return llvm::GlobalVariable::CommonLinkage; // selectany symbols are externally visible, so use weak instead of // linkonce. MSVC optimizes away references to const selectany globals, so // all definitions should be the same and ODR linkage should be used. // http://msdn.microsoft.com/en-us/library/5tkz6s71.aspx if (D->hasAttr()) return llvm::GlobalVariable::WeakODRLinkage; // Otherwise, we have strong external linkage. assert(Linkage == GVA_StrongExternal); return llvm::GlobalVariable::ExternalLinkage; } llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageVarDefinition( const VarDecl *VD, bool IsConstant) { GVALinkage Linkage = getContext().GetGVALinkageForVariable(VD); return getLLVMLinkageForDeclarator(VD, Linkage, IsConstant); } /// Replace the uses of a function that was declared with a non-proto type. /// We want to silently drop extra arguments from call sites static void replaceUsesOfNonProtoConstant(llvm::Constant *old, llvm::Function *newFn) { // Fast path. if (old->use_empty()) return; llvm::Type *newRetTy = newFn->getReturnType(); SmallVector newArgs; for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end(); ui != ue; ) { llvm::Value::use_iterator use = ui++; // Increment before the use is erased. llvm::User *user = use->getUser(); // Recognize and replace uses of bitcasts. Most calls to // unprototyped functions will use bitcasts. if (auto *bitcast = dyn_cast(user)) { if (bitcast->getOpcode() == llvm::Instruction::BitCast) replaceUsesOfNonProtoConstant(bitcast, newFn); continue; } // Recognize calls to the function. llvm::CallSite callSite(user); if (!callSite) continue; if (!callSite.isCallee(&*use)) continue; // If the return types don't match exactly, then we can't // transform this call unless it's dead. if (callSite->getType() != newRetTy && !callSite->use_empty()) continue; // Get the call site's attribute list. SmallVector newAttrs; llvm::AttributeSet oldAttrs = callSite.getAttributes(); // Collect any return attributes from the call. if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex)) newAttrs.push_back( llvm::AttributeSet::get(newFn->getContext(), oldAttrs.getRetAttributes())); // If the function was passed too few arguments, don't transform. unsigned newNumArgs = newFn->arg_size(); if (callSite.arg_size() < newNumArgs) continue; // If extra arguments were passed, we silently drop them. // If any of the types mismatch, we don't transform. unsigned argNo = 0; bool dontTransform = false; for (llvm::Function::arg_iterator ai = newFn->arg_begin(), ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) { if (callSite.getArgument(argNo)->getType() != ai->getType()) { dontTransform = true; break; } // Add any parameter attributes. if (oldAttrs.hasAttributes(argNo + 1)) newAttrs. push_back(llvm:: AttributeSet::get(newFn->getContext(), oldAttrs.getParamAttributes(argNo + 1))); } if (dontTransform) continue; if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(), oldAttrs.getFnAttributes())); // Okay, we can transform this. Create the new call instruction and copy // over the required information. newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo); llvm::CallSite newCall; if (callSite.isCall()) { newCall = llvm::CallInst::Create(newFn, newArgs, "", callSite.getInstruction()); } else { auto *oldInvoke = cast(callSite.getInstruction()); newCall = llvm::InvokeInst::Create(newFn, oldInvoke->getNormalDest(), oldInvoke->getUnwindDest(), newArgs, "", callSite.getInstruction()); } newArgs.clear(); // for the next iteration if (!newCall->getType()->isVoidTy()) newCall->takeName(callSite.getInstruction()); newCall.setAttributes( llvm::AttributeSet::get(newFn->getContext(), newAttrs)); newCall.setCallingConv(callSite.getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. if (!callSite->use_empty()) callSite->replaceAllUsesWith(newCall.getInstruction()); // Copy debug location attached to CI. if (!callSite->getDebugLoc().isUnknown()) newCall->setDebugLoc(callSite->getDebugLoc()); callSite->eraseFromParent(); } } /// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we /// implement a function with no prototype, e.g. "int foo() {}". If there are /// existing call uses of the old function in the module, this adjusts them to /// call the new function directly. /// /// This is not just a cleanup: the always_inline pass requires direct calls to /// functions to be able to inline them. If there is a bitcast in the way, it /// won't inline them. Instcombine normally deletes these calls, but it isn't /// run at -O0. static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Function *NewFn) { // If we're redefining a global as a function, don't transform it. if (!isa(Old)) return; replaceUsesOfNonProtoConstant(Old, NewFn); } void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind(); // If we have a definition, this might be a deferred decl. If the // instantiation is explicit, make sure we emit it at the end. if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition) GetAddrOfGlobalVar(VD); EmitTopLevelDecl(VD); } void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); // Get or create the prototype for the function. if (!GV) { llvm::Constant *C = GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer*/ true); // Strip off a bitcast if we got one back. if (auto *CE = dyn_cast(C)) { assert(CE->getOpcode() == llvm::Instruction::BitCast); GV = cast(CE->getOperand(0)); } else { GV = cast(C); } } if (!GV->isDeclaration()) { getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name); GlobalDecl OldGD = Manglings.lookup(GV->getName()); if (auto *Prev = OldGD.getDecl()) getDiags().Report(Prev->getLocation(), diag::note_previous_definition); return; } if (GV->getType()->getElementType() != Ty) { // If the types mismatch then we have to rewrite the definition. assert(GV->isDeclaration() && "Shouldn't replace non-declaration"); // F is the Function* for the one with the wrong type, we must make a new // Function* and update everything that used F (a declaration) with the new // Function* (which will be a definition). // // This happens if there is a prototype for a function // (e.g. "int f()") and then a definition of a different type // (e.g. "int f(int x)"). Move the old function aside so that it // doesn't interfere with GetAddrOfFunction. GV->setName(StringRef()); auto *NewFn = cast(GetAddrOfFunction(GD, Ty)); // This might be an implementation of a function without a // prototype, in which case, try to do special replacement of // calls which match the new prototype. The really key thing here // is that we also potentially drop arguments from the call site // so as to make a direct call, which makes the inliner happier // and suppresses a number of optimizer warnings (!) about // dropping arguments. if (!GV->use_empty()) { ReplaceUsesOfNonProtoTypeWithRealFunction(GV, NewFn); GV->removeDeadConstantUsers(); } // Replace uses of F with the Function we will endow with a body. if (!GV->use_empty()) { llvm::Constant *NewPtrForOldDecl = llvm::ConstantExpr::getBitCast(NewFn, GV->getType()); GV->replaceAllUsesWith(NewPtrForOldDecl); } // Ok, delete the old function now, which is dead. GV->eraseFromParent(); GV = NewFn; } // We need to set linkage and visibility on the function before // generating code for it because various parts of IR generation // want to propagate this information down (e.g. to local static // declarations). auto *Fn = cast(GV); setFunctionLinkage(GD, Fn); if (D->hasAttr()) GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); else if (D->hasAttr()) GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); else GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); // FIXME: this is redundant with part of setFunctionDefinitionAttributes setGlobalVisibility(Fn, D); MaybeHandleStaticInExternC(D, Fn); CodeGenFunction(*this).GenerateCode(D, Fn, FI); setFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); if (const ConstructorAttr *CA = D->getAttr()) AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr()) AddGlobalDtor(Fn, DA->getPriority()); if (D->hasAttr()) AddGlobalAnnotations(D, Fn); } void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { const auto *D = cast(GD.getDecl()); const AliasAttr *AA = D->getAttr(); assert(AA && "Not an alias?"); StringRef MangledName = getMangledName(GD); // If there is a definition in the module, then it wins over the alias. // This is dubious, but allow it to be safe. Just ignore the alias. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry && !Entry->isDeclaration()) return; Aliases.push_back(GD); llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. llvm::Constant *Aliasee; if (isa(DeclTy)) Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD, /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), /*D=*/nullptr); // Create the new alias itself, but don't set a name yet. auto *GA = llvm::GlobalAlias::create( cast(Aliasee->getType())->getElementType(), 0, llvm::Function::ExternalLinkage, "", Aliasee, &getModule()); if (Entry) { if (GA->getAliasee() == Entry) { Diags.Report(AA->getLocation(), diag::err_cyclic_alias); return; } assert(Entry->isDeclaration()); // If there is a declaration in the module, then we had an extern followed // by the alias, as in: // extern int test6(); // ... // int test6() __attribute__((alias("test7"))); // // Remove it and replace uses of it with the alias. GA->takeName(Entry); Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA, Entry->getType())); Entry->eraseFromParent(); } else { GA->setName(MangledName); } // Set attributes which are particular to an alias; this is a // specialization of the attributes which may be set on a global // variable/function. if (D->hasAttr() || D->hasAttr() || D->isWeakImported()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } if (const auto *VD = dyn_cast(D)) if (VD->getTLSKind()) setTLSMode(GA, *VD); setAliasAttributes(D, GA); } llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef Tys) { return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, Tys); } static llvm::StringMapEntry & GetConstantCFStringEntry(llvm::StringMap &Map, const StringLiteral *Literal, bool TargetIsLSB, bool &IsUTF16, unsigned &StringLength) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); // Check for simple case. if (!Literal->containsNonAsciiOrNull()) { StringLength = NumBytes; return *Map.insert(std::make_pair(String, nullptr)).first; } // Otherwise, convert the UTF8 literals into a string of shorts. IsUTF16 = true; SmallVector ToBuf(NumBytes + 1); // +1 for ending nulls. const UTF8 *FromPtr = (const UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; (void)ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr, ToPtr + NumBytes, strictConversion); // ConvertUTF8toUTF16 returns the length in ToPtr. StringLength = ToPtr - &ToBuf[0]; // Add an explicit null. *ToPtr = 0; return *Map.insert(std::make_pair( StringRef(reinterpret_cast(ToBuf.data()), (StringLength + 1) * 2), nullptr)).first; } static llvm::StringMapEntry & GetConstantStringEntry(llvm::StringMap &Map, const StringLiteral *Literal, unsigned &StringLength) { StringRef String = Literal->getString(); StringLength = String.size(); return *Map.insert(std::make_pair(String, nullptr)).first; } llvm::Constant * CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { unsigned StringLength = 0; bool isUTF16 = false; llvm::StringMapEntry &Entry = GetConstantCFStringEntry(CFConstantStringMap, Literal, getDataLayout().isLittleEndian(), isUTF16, StringLength); if (auto *C = Entry.second) return C; llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; llvm::Value *V; // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); Ty = llvm::ArrayType::get(Ty, 0); llvm::Constant *GV = CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"); // Decay array -> ptr V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); CFConstantStringClassRef = V; } else V = CFConstantStringClassRef; QualType CFTy = getContext().getCFConstantStringType(); auto *STy = cast(getTypes().ConvertType(CFTy)); llvm::Constant *Fields[4]; // Class pointer. Fields[0] = cast(V); // Flags. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) : llvm::ConstantInt::get(Ty, 0x07C8); // String pointer. llvm::Constant *C = nullptr; if (isUTF16) { ArrayRef Arr = llvm::makeArrayRef( reinterpret_cast(const_cast(Entry.first().data())), Entry.first().size() / 2); C = llvm::ConstantDataArray::get(VMContext, Arr); } else { C = llvm::ConstantDataArray::getString(VMContext, Entry.first()); } // Note: -fwritable-strings doesn't make the backing store strings of // CFStrings writable. (See ) auto *GV = new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, C, ".str"); GV->setUnnamedAddr(true); // Don't enforce the target's minimum global alignment, since the only use // of the string is via this class initializer. // FIXME: We set the section explicitly to avoid a bug in ld64 224.1. Without // it LLVM can merge the string with a non unnamed_addr one during LTO. Doing // that changes the section it ends in, which surprises ld64. if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); GV->setSection("__TEXT,__ustring"); } else { CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); GV->setSection("__TEXT,__cstring,cstring_literals"); } // String. Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); if (isUTF16) // Cast the UTF16 string to the correct type. Fields[2] = llvm::ConstantExpr::getBitCast(Fields[2], Int8PtrTy); // String length. Ty = getTypes().ConvertType(getContext().LongTy); Fields[3] = llvm::ConstantInt::get(Ty, StringLength); // The struct. C = llvm::ConstantStruct::get(STy, Fields); GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_cfstring_"); GV->setSection("__DATA,__cfstring"); Entry.second = GV; return GV; } llvm::Constant * CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { unsigned StringLength = 0; llvm::StringMapEntry &Entry = GetConstantStringEntry(CFConstantStringMap, Literal, StringLength); if (auto *C = Entry.second) return C; llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; llvm::Value *V; // If we don't already have it, get _NSConstantStringClassReference. if (!ConstantStringClassRef) { std::string StringClass(getLangOpts().ObjCConstantStringClass); llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); llvm::Constant *GV; if (LangOpts.ObjCRuntime.isNonFragile()) { std::string str = StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" : "OBJC_CLASS_$_" + StringClass; GV = getObjCRuntime().GetClassGlobal(str); // Make sure the result is of the correct type. llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); V = llvm::ConstantExpr::getBitCast(GV, PTy); ConstantStringClassRef = V; } else { std::string str = StringClass.empty() ? "_NSConstantStringClassReference" : "_" + StringClass + "ClassReference"; llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); GV = CreateRuntimeVariable(PTy, str); // Decay array -> ptr V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); ConstantStringClassRef = V; } } else V = ConstantStringClassRef; if (!NSConstantStringType) { // Construct the type for a constant NSString. RecordDecl *D = Context.buildImplicitRecord("__builtin_NSString"); D->startDefinition(); QualType FieldTypes[3]; // const int *isa; FieldTypes[0] = Context.getPointerType(Context.IntTy.withConst()); // const char *str; FieldTypes[1] = Context.getPointerType(Context.CharTy.withConst()); // unsigned int length; FieldTypes[2] = Context.UnsignedIntTy; // Create fields for (unsigned i = 0; i < 3; ++i) { FieldDecl *Field = FieldDecl::Create(Context, D, SourceLocation(), SourceLocation(), nullptr, FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); } D->completeDefinition(); QualType NSTy = Context.getTagDeclType(D); NSConstantStringType = cast(getTypes().ConvertType(NSTy)); } llvm::Constant *Fields[3]; // Class pointer. Fields[0] = cast(V); // String pointer. llvm::Constant *C = llvm::ConstantDataArray::getString(VMContext, Entry.first()); llvm::GlobalValue::LinkageTypes Linkage; bool isConstant; Linkage = llvm::GlobalValue::PrivateLinkage; isConstant = !LangOpts.WritableStrings; auto *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); // Don't enforce the target's minimum global alignment, since the only use // of the string is via this class initializer. CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); // String length. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); Fields[2] = llvm::ConstantInt::get(Ty, StringLength); // The struct. C = llvm::ConstantStruct::get(NSConstantStringType, Fields); GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_nsstring_"); const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip"; const char *NSStringNonFragileABISection = "__DATA,__objc_stringobj,regular,no_dead_strip"; // FIXME. Fix section. GV->setSection(LangOpts.ObjCRuntime.isNonFragile() ? NSStringNonFragileABISection : NSStringSection); Entry.second = GV; return GV; } QualType CodeGenModule::getObjCFastEnumerationStateType() { if (ObjCFastEnumerationStateType.isNull()) { RecordDecl *D = Context.buildImplicitRecord("__objcFastEnumerationState"); D->startDefinition(); QualType FieldTypes[] = { Context.UnsignedLongTy, Context.getPointerType(Context.getObjCIdType()), Context.getPointerType(Context.UnsignedLongTy), Context.getConstantArrayType(Context.UnsignedLongTy, llvm::APInt(32, 5), ArrayType::Normal, 0) }; for (size_t i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(Context, D, SourceLocation(), SourceLocation(), nullptr, FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); } D->completeDefinition(); ObjCFastEnumerationStateType = Context.getTagDeclType(D); } return ObjCFastEnumerationStateType; } llvm::Constant * CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { assert(!E->getType()->isPointerType() && "Strings are always arrays"); // Don't emit it as the address of the string, emit the string data itself // as an inline array. if (E->getCharByteWidth() == 1) { SmallString<64> Str(E->getString()); // Resize the string to the right size, which is indicated by its type. const ConstantArrayType *CAT = Context.getAsConstantArrayType(E->getType()); Str.resize(CAT->getSize().getZExtValue()); return llvm::ConstantDataArray::getString(VMContext, Str, false); } auto *AType = cast(getTypes().ConvertType(E->getType())); llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); // Wide strings have either 2-byte or 4-byte elements. if (ElemTy->getPrimitiveSizeInBits() == 16) { SmallVector Elements; Elements.reserve(NumElements); for(unsigned i = 0, e = E->getLength(); i != e; ++i) Elements.push_back(E->getCodeUnit(i)); Elements.resize(NumElements); return llvm::ConstantDataArray::get(VMContext, Elements); } assert(ElemTy->getPrimitiveSizeInBits() == 32); SmallVector Elements; Elements.reserve(NumElements); for(unsigned i = 0, e = E->getLength(); i != e; ++i) Elements.push_back(E->getCodeUnit(i)); Elements.resize(NumElements); return llvm::ConstantDataArray::get(VMContext, Elements); } static llvm::GlobalVariable * GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT, CodeGenModule &CGM, StringRef GlobalName, unsigned Alignment) { // OpenCL v1.2 s6.5.3: a string literal is in the constant address space. unsigned AddrSpace = 0; if (CGM.getLangOpts().OpenCL) AddrSpace = CGM.getContext().getTargetAddressSpace(LangAS::opencl_constant); // Create a global variable for this string auto *GV = new llvm::GlobalVariable( CGM.getModule(), C->getType(), !CGM.getLangOpts().WritableStrings, LT, C, GlobalName, nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace); GV->setAlignment(Alignment); GV->setUnnamedAddr(true); return GV; } /// GetAddrOfConstantStringFromLiteral - Return a pointer to a /// constant array for the given string literal. llvm::GlobalVariable * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S, StringRef Name) { auto Alignment = getContext().getAlignOfGlobalVarInChars(S->getType()).getQuantity(); llvm::Constant *C = GetConstantArrayFromStringLiteral(S); llvm::GlobalVariable **Entry = nullptr; if (!LangOpts.WritableStrings) { Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { if (Alignment > GV->getAlignment()) GV->setAlignment(Alignment); return GV; } } SmallString<256> MangledNameBuffer; StringRef GlobalVariableName; llvm::GlobalValue::LinkageTypes LT; // Mangle the string literal if the ABI allows for it. However, we cannot // do this if we are compiling with ASan or -fwritable-strings because they // rely on strings having normal linkage. if (!LangOpts.WritableStrings && !LangOpts.Sanitize.has(SanitizerKind::Address) && getCXXABI().getMangleContext().shouldMangleStringLiteral(S)) { llvm::raw_svector_ostream Out(MangledNameBuffer); getCXXABI().getMangleContext().mangleStringLiteral(S, Out); Out.flush(); LT = llvm::GlobalValue::LinkOnceODRLinkage; GlobalVariableName = MangledNameBuffer; } else { LT = llvm::GlobalValue::PrivateLinkage; GlobalVariableName = Name; } auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment); if (Entry) *Entry = GV; SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "", QualType()); return GV; } /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant /// array for the given ObjCEncodeExpr node. llvm::GlobalVariable * CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { std::string Str; getContext().getObjCEncodingForType(E->getEncodedType(), Str); return GetAddrOfConstantCString(Str); } /// GetAddrOfConstantCString - Returns a pointer to a character array containing /// the literal and a terminating '\0' character. /// The result has pointer to array type. llvm::GlobalVariable *CodeGenModule::GetAddrOfConstantCString( const std::string &Str, const char *GlobalName, unsigned Alignment) { StringRef StrWithNull(Str.c_str(), Str.size() + 1); if (Alignment == 0) { Alignment = getContext() .getAlignOfGlobalVarInChars(getContext().CharTy) .getQuantity(); } llvm::Constant *C = llvm::ConstantDataArray::getString(getLLVMContext(), StrWithNull, false); // Don't share any string literals if strings aren't constant. llvm::GlobalVariable **Entry = nullptr; if (!LangOpts.WritableStrings) { Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { if (Alignment > GV->getAlignment()) GV->setAlignment(Alignment); return GV; } } // Get the default prefix if a name wasn't specified. if (!GlobalName) GlobalName = ".str"; // Create a global variable for this. auto GV = GenerateStringLiteral(C, llvm::GlobalValue::PrivateLinkage, *this, GlobalName, Alignment); if (Entry) *Entry = GV; return GV; } llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary( const MaterializeTemporaryExpr *E, const Expr *Init) { assert((E->getStorageDuration() == SD_Static || E->getStorageDuration() == SD_Thread) && "not a global temporary"); const auto *VD = cast(E->getExtendingDecl()); // If we're not materializing a subobject of the temporary, keep the // cv-qualifiers from the type of the MaterializeTemporaryExpr. QualType MaterializedType = Init->getType(); if (Init == E->GetTemporaryExpr()) MaterializedType = E->getType(); llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E]; if (Slot) return Slot; // FIXME: If an externally-visible declaration extends multiple temporaries, // we need to give each temporary the same name in every translation unit (and // we also need to make the temporaries externally-visible). SmallString<256> Name; llvm::raw_svector_ostream Out(Name); getCXXABI().getMangleContext().mangleReferenceTemporary( VD, E->getManglingNumber(), Out); Out.flush(); APValue *Value = nullptr; if (E->getStorageDuration() == SD_Static) { // We might have a cached constant initializer for this temporary. Note // that this might have a different value from the value computed by // evaluating the initializer if the surrounding constant expression // modifies the temporary. Value = getContext().getMaterializedTemporaryValue(E, false); if (Value && Value->isUninit()) Value = nullptr; } // Try evaluating it now, it might have a constant initializer. Expr::EvalResult EvalResult; if (!Value && Init->EvaluateAsRValue(EvalResult, getContext()) && !EvalResult.hasSideEffects()) Value = &EvalResult.Val; llvm::Constant *InitialValue = nullptr; bool Constant = false; llvm::Type *Type; if (Value) { // The temporary has a constant initializer, use it. InitialValue = EmitConstantValue(*Value, MaterializedType, nullptr); Constant = isTypeConstant(MaterializedType, /*ExcludeCtor*/Value); Type = InitialValue->getType(); } else { // No initializer, the initialization will be provided when we // initialize the declaration which performed lifetime extension. Type = getTypes().ConvertTypeForMem(MaterializedType); } // Create a global variable for this lifetime-extended temporary. llvm::GlobalValue::LinkageTypes Linkage = getLLVMLinkageVarDefinition(VD, Constant); // There is no need for this temporary to have global linkage if the global // variable has external linkage. if (Linkage == llvm::GlobalVariable::ExternalLinkage) Linkage = llvm::GlobalVariable::PrivateLinkage; unsigned AddrSpace = GetGlobalVarAddressSpace( VD, getContext().getTargetAddressSpace(MaterializedType)); auto *GV = new llvm::GlobalVariable( getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(), /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace); setGlobalVisibility(GV, VD); GV->setAlignment( getContext().getTypeAlignInChars(MaterializedType).getQuantity()); if (VD->getTLSKind()) setTLSMode(GV, *VD); Slot = GV; return GV; } /// EmitObjCPropertyImplementations - Emit information for synthesized /// properties for an implementation. void CodeGenModule::EmitObjCPropertyImplementations(const ObjCImplementationDecl *D) { for (const auto *PID : D->property_impls()) { // Dynamic is just for type-checking. if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *PD = PID->getPropertyDecl(); // Determine which methods need to be implemented, some may have // been overridden. Note that ::isPropertyAccessor is not the method // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. if (!D->getInstanceMethod(PD->getGetterName())) CodeGenFunction(*this).GenerateObjCGetter( const_cast(D), PID); if (!PD->isReadOnly() && !D->getInstanceMethod(PD->getSetterName())) CodeGenFunction(*this).GenerateObjCSetter( const_cast(D), PID); } } } static bool needsDestructMethod(ObjCImplementationDecl *impl) { const ObjCInterfaceDecl *iface = impl->getClassInterface(); for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); ivar; ivar = ivar->getNextIvar()) if (ivar->getType().isDestructedType()) return true; return false; } static bool AllTrivialInitializers(CodeGenModule &CGM, ObjCImplementationDecl *D) { CodeGenFunction CGF(CGM); for (ObjCImplementationDecl::init_iterator B = D->init_begin(), E = D->init_end(); B != E; ++B) { CXXCtorInitializer *CtorInitExp = *B; Expr *Init = CtorInitExp->getInit(); if (!CGF.isTrivialInitializer(Init)) return false; } return true; } /// EmitObjCIvarInitializations - Emit information for ivar initialization /// for an implementation. void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // We might need a .cxx_destruct even if we don't have any ivar initializers. if (needsDestructMethod(D)) { IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().VoidTy, nullptr, D, /*isInstance=*/true, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); D->setHasDestructors(true); } // If the implementation doesn't have any ivar initializers, we don't need // a .cxx_construct. if (D->getNumIvarInitializers() == 0 || AllTrivialInitializers(*this, D)) return; IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); D->setHasNonZeroConstructors(true); } /// EmitNamespace - Emit all declarations in a namespace. void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { for (auto *I : ND->decls()) { if (const auto *VD = dyn_cast(I)) if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && VD->getTemplateSpecializationKind() != TSK_Undeclared) continue; EmitTopLevelDecl(I); } } // EmitLinkageSpec - Emit all declarations in a linkage spec. void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) { if (LSD->getLanguage() != LinkageSpecDecl::lang_c && LSD->getLanguage() != LinkageSpecDecl::lang_cxx) { ErrorUnsupported(LSD, "linkage spec"); return; } for (auto *I : LSD->decls()) { // Meta-data for ObjC class includes references to implemented methods. // Generate class's method definitions first. if (auto *OID = dyn_cast(I)) { for (auto *M : OID->methods()) EmitTopLevelDecl(M); } EmitTopLevelDecl(I); } } /// EmitTopLevelDecl - Emit code for a single top level declaration. void CodeGenModule::EmitTopLevelDecl(Decl *D) { // Ignore dependent declarations. if (D->getDeclContext() && D->getDeclContext()->isDependentContext()) return; switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: case Decl::Function: // Skip function templates if (cast(D)->getDescribedFunctionTemplate() || cast(D)->isLateTemplateParsed()) return; EmitGlobal(cast(D)); // Always provide some coverage mapping // even for the functions that aren't emitted. AddDeferredUnusedCoverageMapping(D); break; case Decl::Var: // Skip variable templates if (cast(D)->getDescribedVarTemplate()) return; case Decl::VarTemplateSpecialization: EmitGlobal(cast(D)); break; // Indirect fields from global anonymous structs and unions can be // ignored; only the actual variable requires IR gen support. case Decl::IndirectField: break; // C++ Decls case Decl::Namespace: EmitNamespace(cast(D)); break; // No code generation needed. case Decl::UsingShadow: case Decl::ClassTemplate: case Decl::VarTemplate: case Decl::VarTemplatePartialSpecialization: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::Block: case Decl::Empty: break; case Decl::Using: // using X; [C++] if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitUsingDecl(cast(*D)); return; case Decl::NamespaceAlias: if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitNamespaceAlias(cast(*D)); return; case Decl::UsingDirective: // using namespace X; [C++] if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitUsingDirective(cast(*D)); return; case Decl::CXXConstructor: // Skip function templates if (cast(D)->getDescribedFunctionTemplate() || cast(D)->isLateTemplateParsed()) return; getCXXABI().EmitCXXConstructors(cast(D)); break; case Decl::CXXDestructor: if (cast(D)->isLateTemplateParsed()) return; getCXXABI().EmitCXXDestructors(cast(D)); break; case Decl::StaticAssert: // Nothing to do. break; // Objective-C Decls // Forward declarations, no (immediate) code generation. case Decl::ObjCInterface: case Decl::ObjCCategory: break; case Decl::ObjCProtocol: { auto *Proto = cast(D); if (Proto->isThisDeclarationADefinition()) ObjCRuntime->GenerateProtocol(Proto); break; } case Decl::ObjCCategoryImpl: // Categories have properties but don't support synthesize so we // can ignore them here. ObjCRuntime->GenerateCategory(cast(D)); break; case Decl::ObjCImplementation: { auto *OMD = cast(D); EmitObjCPropertyImplementations(OMD); EmitObjCIvarInitializations(OMD); ObjCRuntime->GenerateClass(OMD); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType( OMD->getClassInterface()), OMD->getLocation()); break; } case Decl::ObjCMethod: { auto *OMD = cast(D); // If this is not a prototype, emit the body. if (OMD->getBody()) CodeGenFunction(*this).GenerateObjCMethod(OMD); break; } case Decl::ObjCCompatibleAlias: ObjCRuntime->RegisterAlias(cast(D)); break; case Decl::LinkageSpec: EmitLinkageSpec(cast(D)); break; case Decl::FileScopeAsm: { auto *AD = cast(D); StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); else if (S.end()[-1] == '\n') getModule().setModuleInlineAsm(S + AsmString.str()); else getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; } case Decl::Import: { auto *Import = cast(D); // Ignore import declarations that come from imported modules. if (clang::Module *Owner = Import->getOwningModule()) { if (getLangOpts().CurrentModule.empty() || Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule) break; } ImportedModules.insert(Import->getImportedModule()); break; } case Decl::OMPThreadPrivate: EmitOMPThreadPrivateDecl(cast(D)); break; case Decl::ClassTemplateSpecialization: { const auto *Spec = cast(D); if (DebugInfo && Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition && Spec->hasDefinition()) DebugInfo->completeTemplateDefinition(*Spec); break; } default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind // function. Need to recode Decl::Kind to do that easily. assert(isa(D) && "Unsupported decl kind"); break; } } void CodeGenModule::AddDeferredUnusedCoverageMapping(Decl *D) { // Do we need to generate coverage mapping? if (!CodeGenOpts.CoverageMapping) return; switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: case Decl::Function: case Decl::ObjCMethod: case Decl::CXXConstructor: case Decl::CXXDestructor: { if (!cast(D)->hasBody()) return; auto I = DeferredEmptyCoverageMappingDecls.find(D); if (I == DeferredEmptyCoverageMappingDecls.end()) DeferredEmptyCoverageMappingDecls[D] = true; break; } default: break; }; } void CodeGenModule::ClearUnusedCoverageMapping(const Decl *D) { // Do we need to generate coverage mapping? if (!CodeGenOpts.CoverageMapping) return; if (const auto *Fn = dyn_cast(D)) { if (Fn->isTemplateInstantiation()) ClearUnusedCoverageMapping(Fn->getTemplateInstantiationPattern()); } auto I = DeferredEmptyCoverageMappingDecls.find(D); if (I == DeferredEmptyCoverageMappingDecls.end()) DeferredEmptyCoverageMappingDecls[D] = false; else I->second = false; } void CodeGenModule::EmitDeferredUnusedCoverageMappings() { std::vector DeferredDecls; for (const auto I : DeferredEmptyCoverageMappingDecls) { if (!I.second) continue; DeferredDecls.push_back(I.first); } // Sort the declarations by their location to make sure that the tests get a // predictable order for the coverage mapping for the unused declarations. if (CodeGenOpts.DumpCoverageMapping) std::sort(DeferredDecls.begin(), DeferredDecls.end(), [] (const Decl *LHS, const Decl *RHS) { return LHS->getLocStart() < RHS->getLocStart(); }); for (const auto *D : DeferredDecls) { switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: case Decl::Function: case Decl::ObjCMethod: { CodeGenPGO PGO(*this); GlobalDecl GD(cast(D)); PGO.emitEmptyCounterMapping(D, getMangledName(GD), getFunctionLinkage(GD)); break; } case Decl::CXXConstructor: { CodeGenPGO PGO(*this); GlobalDecl GD(cast(D), Ctor_Base); PGO.emitEmptyCounterMapping(D, getMangledName(GD), getFunctionLinkage(GD)); break; } case Decl::CXXDestructor: { CodeGenPGO PGO(*this); GlobalDecl GD(cast(D), Dtor_Base); PGO.emitEmptyCounterMapping(D, getMangledName(GD), getFunctionLinkage(GD)); break; } default: break; }; } } /// Turns the given pointer into a constant. static llvm::Constant *GetPointerConstant(llvm::LLVMContext &Context, const void *Ptr) { uintptr_t PtrInt = reinterpret_cast(Ptr); llvm::Type *i64 = llvm::Type::getInt64Ty(Context); return llvm::ConstantInt::get(i64, PtrInt); } static void EmitGlobalDeclMetadata(CodeGenModule &CGM, llvm::NamedMDNode *&GlobalMetadata, GlobalDecl D, llvm::GlobalValue *Addr) { if (!GlobalMetadata) GlobalMetadata = CGM.getModule().getOrInsertNamedMetadata("clang.global.decl.ptrs"); // TODO: should we report variant information for ctors/dtors? llvm::Metadata *Ops[] = {llvm::ConstantAsMetadata::get(Addr), llvm::ConstantAsMetadata::get(GetPointerConstant( CGM.getLLVMContext(), D.getDecl()))}; GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } /// For each function which is declared within an extern "C" region and marked /// as 'used', but has internal linkage, create an alias from the unmangled /// name to the mangled name if possible. People expect to be able to refer /// to such functions with an unmangled name from inline assembly within the /// same translation unit. void CodeGenModule::EmitStaticExternCAliases() { for (StaticExternCMap::iterator I = StaticExternCValues.begin(), E = StaticExternCValues.end(); I != E; ++I) { IdentifierInfo *Name = I->first; llvm::GlobalValue *Val = I->second; if (Val && !getModule().getNamedValue(Name->getName())) addUsedGlobal(llvm::GlobalAlias::create(Name->getName(), Val)); } } bool CodeGenModule::lookupRepresentativeDecl(StringRef MangledName, GlobalDecl &Result) const { auto Res = Manglings.find(MangledName); if (Res == Manglings.end()) return false; Result = Res->getValue(); return true; } /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. /// /// Since there's currently no way to associate an MDNode directly /// with an llvm::GlobalValue, we create a global named metadata /// with the name 'clang.global.decl.ptrs'. void CodeGenModule::EmitDeclMetadata() { llvm::NamedMDNode *GlobalMetadata = nullptr; // StaticLocalDeclMap for (auto &I : MangledDeclNames) { llvm::GlobalValue *Addr = getModule().getNamedValue(I.second); EmitGlobalDeclMetadata(*this, GlobalMetadata, I.first, Addr); } } /// Emits metadata nodes for all the local variables in the current /// function. void CodeGenFunction::EmitDeclMetadata() { if (LocalDeclMap.empty()) return; llvm::LLVMContext &Context = getLLVMContext(); // Find the unique metadata ID for this name. unsigned DeclPtrKind = Context.getMDKindID("clang.decl.ptr"); llvm::NamedMDNode *GlobalMetadata = nullptr; for (auto &I : LocalDeclMap) { const Decl *D = I.first; llvm::Value *Addr = I.second; if (auto *Alloca = dyn_cast(Addr)) { llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); Alloca->setMetadata( DeclPtrKind, llvm::MDNode::get( Context, llvm::ValueAsMetadata::getConstant(DAddr))); } else if (auto *GV = dyn_cast(Addr)) { GlobalDecl GD = GlobalDecl(cast(D)); EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV); } } } void CodeGenModule::EmitVersionIdentMetadata() { llvm::NamedMDNode *IdentMetadata = TheModule.getOrInsertNamedMetadata("llvm.ident"); std::string Version = getClangFullVersion(); llvm::LLVMContext &Ctx = TheModule.getContext(); llvm::Metadata *IdentNode[] = {llvm::MDString::get(Ctx, Version)}; IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode)); } void CodeGenModule::EmitTargetMetadata() { // Warning, new MangledDeclNames may be appended within this loop. // We rely on MapVector insertions adding new elements to the end // of the container. // FIXME: Move this loop into the one target that needs it, and only // loop over those declarations for which we couldn't emit the target // metadata when we emitted the declaration. for (unsigned I = 0; I != MangledDeclNames.size(); ++I) { auto Val = *(MangledDeclNames.begin() + I); const Decl *D = Val.first.getDecl()->getMostRecentDecl(); llvm::GlobalValue *GV = GetGlobalValue(Val.second); getTargetCodeGenInfo().emitTargetMD(D, GV, *this); } } void CodeGenModule::EmitCoverageFile() { if (!getCodeGenOpts().CoverageFile.empty()) { if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) { llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov"); llvm::LLVMContext &Ctx = TheModule.getContext(); llvm::MDString *CoverageFile = llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile); for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) { llvm::MDNode *CU = CUNode->getOperand(i); llvm::Metadata *Elts[] = {CoverageFile, CU}; GCov->addOperand(llvm::MDNode::get(Ctx, Elts)); } } } } llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid) { // Sema has checked that all uuid strings are of the form // "12345678-1234-1234-1234-1234567890ab". assert(Uuid.size() == 36); for (unsigned i = 0; i < 36; ++i) { if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuid[i] == '-'); else assert(isHexDigit(Uuid[i])); } // The starts of all bytes of Field3 in Uuid. Field 3 is "1234-1234567890ab". const unsigned Field3ValueOffsets[8] = { 19, 21, 24, 26, 28, 30, 32, 34 }; llvm::Constant *Field3[8]; for (unsigned Idx = 0; Idx < 8; ++Idx) Field3[Idx] = llvm::ConstantInt::get( Int8Ty, Uuid.substr(Field3ValueOffsets[Idx], 2), 16); llvm::Constant *Fields[4] = { llvm::ConstantInt::get(Int32Ty, Uuid.substr(0, 8), 16), llvm::ConstantInt::get(Int16Ty, Uuid.substr(9, 4), 16), llvm::ConstantInt::get(Int16Ty, Uuid.substr(14, 4), 16), llvm::ConstantArray::get(llvm::ArrayType::get(Int8Ty, 8), Field3) }; return llvm::ConstantStruct::getAnon(Fields); } llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH) { // Return a bogus pointer if RTTI is disabled, unless it's for EH. // FIXME: should we even be calling this method if RTTI is disabled // and it's not for EH? if (!ForEH && !getLangOpts().RTTI) return llvm::Constant::getNullValue(Int8PtrTy); if (ForEH && Ty->isObjCObjectPointerType() && LangOpts.ObjCRuntime.isGNUFamily()) return ObjCRuntime->GetEHType(Ty); return getCXXABI().getAddrOfRTTIDescriptor(Ty); } void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { for (auto RefExpr : D->varlists()) { auto *VD = cast(cast(RefExpr)->getDecl()); bool PerformInit = VD->getAnyInitializer() && !VD->getAnyInitializer()->isConstantInitializer(getContext(), /*ForRef=*/false); if (auto InitFunction = getOpenMPRuntime().EmitOMPThreadPrivateVarDefinition( VD, GetAddrOfGlobalVar(VD), RefExpr->getLocStart(), PerformInit)) CXXGlobalInits.push_back(InitFunction); } } Index: vendor/clang/dist/lib/CodeGen/CodeGenModule.h =================================================================== --- vendor/clang/dist/lib/CodeGen/CodeGenModule.h (revision 278753) +++ vendor/clang/dist/lib/CodeGen/CodeGenModule.h (revision 278754) @@ -1,1220 +1,1220 @@ //===--- CodeGenModule.h - Per-Module state for LLVM CodeGen ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This is the internal per-translation-unit state used for llvm translation. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H #define LLVM_CLANG_LIB_CODEGEN_CODEGENMODULE_H #include "CGVTables.h" #include "CodeGenTypes.h" #include "SanitizerMetadata.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/GlobalDecl.h" #include "clang/AST/Mangle.h" #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/SanitizerBlacklist.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" namespace llvm { class Module; class Constant; class ConstantInt; class Function; class GlobalValue; class DataLayout; class FunctionType; class LLVMContext; class IndexedInstrProfReader; } namespace clang { class TargetCodeGenInfo; class ASTContext; class AtomicType; class FunctionDecl; class IdentifierInfo; class ObjCMethodDecl; class ObjCImplementationDecl; class ObjCCategoryImplDecl; class ObjCProtocolDecl; class ObjCEncodeExpr; class BlockExpr; class CharUnits; class Decl; class Expr; class Stmt; class InitListExpr; class StringLiteral; class NamedDecl; class ValueDecl; class VarDecl; class LangOptions; class CodeGenOptions; class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; class Module; class CoverageSourceInfo; namespace CodeGen { class CallArgList; class CodeGenFunction; class CodeGenTBAA; class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; class CGOpenCLRuntime; class CGOpenMPRuntime; class CGCUDARuntime; class BlockFieldFlags; class FunctionArgList; class CoverageMappingModuleGen; struct OrderGlobalInits { unsigned int priority; unsigned int lex_order; OrderGlobalInits(unsigned int p, unsigned int l) : priority(p), lex_order(l) {} bool operator==(const OrderGlobalInits &RHS) const { return priority == RHS.priority && lex_order == RHS.lex_order; } bool operator<(const OrderGlobalInits &RHS) const { return std::tie(priority, lex_order) < std::tie(RHS.priority, RHS.lex_order); } }; struct CodeGenTypeCache { /// void llvm::Type *VoidTy; /// i8, i16, i32, and i64 llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; /// float, double llvm::Type *FloatTy, *DoubleTy; /// int llvm::IntegerType *IntTy; /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size. union { llvm::IntegerType *IntPtrTy; llvm::IntegerType *SizeTy; llvm::IntegerType *PtrDiffTy; }; /// void* in address space 0 union { llvm::PointerType *VoidPtrTy; llvm::PointerType *Int8PtrTy; }; /// void** in address space 0 union { llvm::PointerType *VoidPtrPtrTy; llvm::PointerType *Int8PtrPtrTy; }; /// The width of a pointer into the generic address space. unsigned char PointerWidthInBits; /// The size and alignment of a pointer into the generic address /// space. union { unsigned char PointerAlignInBytes; unsigned char PointerSizeInBytes; unsigned char SizeSizeInBytes; // sizeof(size_t) }; llvm::CallingConv::ID RuntimeCC; llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; } llvm::CallingConv::ID BuiltinCC; llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; } }; struct RREntrypoints { RREntrypoints() { memset(this, 0, sizeof(*this)); } /// void objc_autoreleasePoolPop(void*); llvm::Constant *objc_autoreleasePoolPop; /// void *objc_autoreleasePoolPush(void); llvm::Constant *objc_autoreleasePoolPush; }; struct ARCEntrypoints { ARCEntrypoints() { memset(this, 0, sizeof(*this)); } /// id objc_autorelease(id); llvm::Constant *objc_autorelease; /// id objc_autoreleaseReturnValue(id); llvm::Constant *objc_autoreleaseReturnValue; /// void objc_copyWeak(id *dest, id *src); llvm::Constant *objc_copyWeak; /// void objc_destroyWeak(id*); llvm::Constant *objc_destroyWeak; /// id objc_initWeak(id*, id); llvm::Constant *objc_initWeak; /// id objc_loadWeak(id*); llvm::Constant *objc_loadWeak; /// id objc_loadWeakRetained(id*); llvm::Constant *objc_loadWeakRetained; /// void objc_moveWeak(id *dest, id *src); llvm::Constant *objc_moveWeak; /// id objc_retain(id); llvm::Constant *objc_retain; /// id objc_retainAutorelease(id); llvm::Constant *objc_retainAutorelease; /// id objc_retainAutoreleaseReturnValue(id); llvm::Constant *objc_retainAutoreleaseReturnValue; /// id objc_retainAutoreleasedReturnValue(id); llvm::Constant *objc_retainAutoreleasedReturnValue; /// id objc_retainBlock(id); llvm::Constant *objc_retainBlock; /// void objc_release(id); llvm::Constant *objc_release; /// id objc_storeStrong(id*, id); llvm::Constant *objc_storeStrong; /// id objc_storeWeak(id*, id); llvm::Constant *objc_storeWeak; /// A void(void) inline asm to use to mark that the return value of /// a call will be immediately retain. llvm::InlineAsm *retainAutoreleasedReturnValueMarker; /// void clang.arc.use(...); llvm::Constant *clang_arc_use; }; /// This class records statistics on instrumentation based profiling. class InstrProfStats { uint32_t VisitedInMainFile; uint32_t MissingInMainFile; uint32_t Visited; uint32_t Missing; uint32_t Mismatched; public: InstrProfStats() : VisitedInMainFile(0), MissingInMainFile(0), Visited(0), Missing(0), Mismatched(0) {} /// Record that we've visited a function and whether or not that function was /// in the main source file. void addVisited(bool MainFile) { if (MainFile) ++VisitedInMainFile; ++Visited; } /// Record that a function we've visited has no profile data. void addMissing(bool MainFile) { if (MainFile) ++MissingInMainFile; ++Missing; } /// Record that a function we've visited has mismatched profile data. void addMismatched(bool MainFile) { ++Mismatched; } /// Whether or not the stats we've gathered indicate any potential problems. bool hasDiagnostics() { return Missing || Mismatched; } /// Report potential problems we've found to \c Diags. void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile); }; /// This class organizes the cross-function state that is used while generating /// LLVM code. class CodeGenModule : public CodeGenTypeCache { CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION; void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION; public: struct Structor { Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {} Structor(int Priority, llvm::Constant *Initializer, llvm::Constant *AssociatedData) : Priority(Priority), Initializer(Initializer), AssociatedData(AssociatedData) {} int Priority; llvm::Constant *Initializer; llvm::Constant *AssociatedData; }; typedef std::vector CtorList; private: ASTContext &Context; const LangOptions &LangOpts; const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; DiagnosticsEngine &Diags; const llvm::DataLayout &TheDataLayout; const TargetInfo &Target; std::unique_ptr ABI; llvm::LLVMContext &VMContext; CodeGenTBAA *TBAA; mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; // This should not be moved earlier, since its initialization depends on some // of the previous reference members being already initialized and also checks // if TheTargetCodeGenInfo is NULL CodeGenTypes Types; /// Holds information about C++ vtables. CodeGenVTables VTables; CGObjCRuntime* ObjCRuntime; CGOpenCLRuntime* OpenCLRuntime; CGOpenMPRuntime* OpenMPRuntime; CGCUDARuntime* CUDARuntime; CGDebugInfo* DebugInfo; ARCEntrypoints *ARCData; llvm::MDNode *NoObjCARCExceptionsMetadata; RREntrypoints *RRData; std::unique_ptr PGOReader; InstrProfStats PGOStats; // A set of references that have only been seen via a weakref so far. This is // used to remove the weak of the reference if we ever see a direct reference // or a definition. llvm::SmallPtrSet WeakRefReferences; /// This contains all the decls which have definitions but/ which are deferred /// for emission and therefore should only be output if they are actually /// used. If a decl is in this, then it is known to have not been referenced /// yet. std::map DeferredDecls; /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. struct DeferredGlobal { DeferredGlobal(llvm::GlobalValue *GV, GlobalDecl GD) : GV(GV), GD(GD) {} - llvm::AssertingVH GV; + llvm::TrackingVH GV; GlobalDecl GD; }; std::vector DeferredDeclsToEmit; void addDeferredDeclToEmit(llvm::GlobalValue *GV, GlobalDecl GD) { DeferredDeclsToEmit.push_back(DeferredGlobal(GV, GD)); } /// List of alias we have emitted. Used to make sure that what they point to /// is defined once we get to the end of the of the translation unit. std::vector Aliases; typedef llvm::StringMap > ReplacementsTy; ReplacementsTy Replacements; /// A queue of (optional) vtables to consider emitting. std::vector DeferredVTables; /// List of global values which are required to be present in the object file; /// bitcast to i8*. This is used for forcing visibility of symbols which may /// otherwise be optimized out. std::vector LLVMUsed; std::vector LLVMCompilerUsed; /// Store the list of global constructors and their respective priorities to /// be emitted when the translation unit is complete. CtorList GlobalCtors; /// Store the list of global destructors and their respective priorities to be /// emitted when the translation unit is complete. CtorList GlobalDtors; /// An ordered map of canonical GlobalDecls to their mangled names. llvm::MapVector MangledDeclNames; llvm::StringMap Manglings; /// Global annotations. std::vector Annotations; /// Map used to get unique annotation strings. llvm::StringMap AnnotationStrings; llvm::StringMap CFConstantStringMap; llvm::DenseMap ConstantStringMap; llvm::DenseMap StaticLocalDeclMap; llvm::DenseMap StaticLocalDeclGuardMap; llvm::DenseMap MaterializedGlobalTemporaryMap; llvm::DenseMap AtomicSetterHelperFnMap; llvm::DenseMap AtomicGetterHelperFnMap; /// Map used to get unique type descriptor constants for sanitizers. llvm::DenseMap TypeDescriptorMap; /// Map used to track internal linkage functions declared within /// extern "C" regions. typedef llvm::MapVector StaticExternCMap; StaticExternCMap StaticExternCValues; /// \brief thread_local variables defined or used in this TU. std::vector > CXXThreadLocals; /// \brief thread_local variables with initializers that need to run /// before any thread_local variable in this TU is odr-used. std::vector CXXThreadLocalInits; std::vector CXXThreadLocalInitVars; /// Global variables with initializers that need to run before main. std::vector CXXGlobalInits; /// When a C++ decl with an initializer is deferred, null is /// appended to CXXGlobalInits, and the index of that null is placed /// here so that the initializer will be performed in the correct /// order. llvm::DenseMap DelayedCXXInitPosition; typedef std::pair GlobalInitData; struct GlobalInitPriorityCmp { bool operator()(const GlobalInitData &LHS, const GlobalInitData &RHS) const { return LHS.first.priority < RHS.first.priority; } }; /// Global variables with initializers whose order of initialization is set by /// init_priority attribute. SmallVector PrioritizedCXXGlobalInits; /// Global destructor functions and arguments that need to run on termination. std::vector > CXXGlobalDtors; /// \brief The complete set of modules that has been imported. llvm::SetVector ImportedModules; /// \brief A vector of metadata strings. SmallVector LinkerOptionsMetadata; /// @name Cache for Objective-C runtime types /// @{ /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. llvm::WeakVH CFConstantStringClassRef; /// Cached reference to the class for constant strings. This value has type /// int * but is actually an Obj-C class pointer. llvm::WeakVH ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType; /// \brief The type used to describe the state of a fast enumeration in /// Objective-C's for..in loop. QualType ObjCFastEnumerationStateType; /// @} /// Lazily create the Objective-C runtime void createObjCRuntime(); void createOpenCLRuntime(); void createOpenMPRuntime(); void createCUDARuntime(); bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(GlobalDecl GD); /// @name Cache for Blocks Runtime Globals /// @{ llvm::Constant *NSConcreteGlobalBlock; llvm::Constant *NSConcreteStackBlock; llvm::Constant *BlockObjectAssign; llvm::Constant *BlockObjectDispose; llvm::Type *BlockDescriptorType; llvm::Type *GenericBlockLiteralType; struct { int GlobalUniqueCount; } Block; /// void @llvm.lifetime.start(i64 %size, i8* nocapture ) llvm::Constant *LifetimeStartFn; /// void @llvm.lifetime.end(i64 %size, i8* nocapture ) llvm::Constant *LifetimeEndFn; GlobalDecl initializedGlobalDecl; std::unique_ptr SanitizerMD; /// @} llvm::DenseMap DeferredEmptyCoverageMappingDecls; std::unique_ptr CoverageMapping; public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &Diags, CoverageSourceInfo *CoverageInfo = nullptr); ~CodeGenModule(); void clear(); /// Finalize LLVM code generation. void Release(); /// Return a reference to the configured Objective-C runtime. CGObjCRuntime &getObjCRuntime() { if (!ObjCRuntime) createObjCRuntime(); return *ObjCRuntime; } /// Return true iff an Objective-C runtime has been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } /// Return a reference to the configured OpenCL runtime. CGOpenCLRuntime &getOpenCLRuntime() { assert(OpenCLRuntime != nullptr); return *OpenCLRuntime; } /// Return a reference to the configured OpenMP runtime. CGOpenMPRuntime &getOpenMPRuntime() { assert(OpenMPRuntime != nullptr); return *OpenMPRuntime; } /// Return a reference to the configured CUDA runtime. CGCUDARuntime &getCUDARuntime() { assert(CUDARuntime != nullptr); return *CUDARuntime; } ARCEntrypoints &getARCEntrypoints() const { assert(getLangOpts().ObjCAutoRefCount && ARCData != nullptr); return *ARCData; } RREntrypoints &getRREntrypoints() const { assert(RRData != nullptr); return *RRData; } InstrProfStats &getPGOStats() { return PGOStats; } llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); } CoverageMappingModuleGen *getCoverageMapping() const { return CoverageMapping.get(); } llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) { return StaticLocalDeclMap[D]; } void setStaticLocalDeclAddress(const VarDecl *D, llvm::Constant *C) { StaticLocalDeclMap[D] = C; } llvm::Constant * getOrCreateStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage); llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) { return StaticLocalDeclGuardMap[D]; } void setStaticLocalDeclGuardAddress(const VarDecl *D, llvm::GlobalVariable *C) { StaticLocalDeclGuardMap[D] = C; } bool lookupRepresentativeDecl(StringRef MangledName, GlobalDecl &Result) const; llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) { return AtomicSetterHelperFnMap[Ty]; } void setAtomicSetterHelperFnMap(QualType Ty, llvm::Constant *Fn) { AtomicSetterHelperFnMap[Ty] = Fn; } llvm::Constant *getAtomicGetterHelperFnMap(QualType Ty) { return AtomicGetterHelperFnMap[Ty]; } void setAtomicGetterHelperFnMap(QualType Ty, llvm::Constant *Fn) { AtomicGetterHelperFnMap[Ty] = Fn; } llvm::Constant *getTypeDescriptorFromMap(QualType Ty) { return TypeDescriptorMap[Ty]; } void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) { TypeDescriptorMap[Ty] = C; } CGDebugInfo *getModuleDebugInfo() { return DebugInfo; } llvm::MDNode *getNoObjCARCExceptionsMetadata() { if (!NoObjCARCExceptionsMetadata) NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None); return NoObjCARCExceptionsMetadata; } ASTContext &getContext() const { return Context; } const LangOptions &getLangOpts() const { return LangOpts; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } llvm::Module &getModule() const { return TheModule; } DiagnosticsEngine &getDiags() const { return Diags; } const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } const TargetInfo &getTarget() const { return Target; } const llvm::Triple &getTriple() const; bool supportsCOMDAT() const; CGCXXABI &getCXXABI() const { return *ABI; } llvm::LLVMContext &getLLVMContext() { return VMContext; } bool shouldUseTBAA() const { return TBAA != nullptr; } const TargetCodeGenInfo &getTargetCodeGenInfo(); CodeGenTypes &getTypes() { return Types; } CodeGenVTables &getVTables() { return VTables; } ItaniumVTableContext &getItaniumVTableContext() { return VTables.getItaniumVTableContext(); } MicrosoftVTableContext &getMicrosoftVTableContext() { return VTables.getMicrosoftVTableContext(); } CtorList &getGlobalCtors() { return GlobalCtors; } CtorList &getGlobalDtors() { return GlobalDtors; } llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); llvm::MDNode *getTBAAStructInfo(QualType QTy); /// Return the MDNode in the type DAG for the given struct type. llvm::MDNode *getTBAAStructTypeInfo(QualType QTy); /// Return the path-aware tag for given base type, access node and offset. llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN, uint64_t O); bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); bool isPaddedAtomicType(QualType type); bool isPaddedAtomicType(const AtomicType *type); /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag /// is the same as the type. For struct-path aware TBAA, the tag /// is different from the type: base type, access type and offset. /// When ConvertTypeToTag is true, we create a tag based on the scalar type. void DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo, bool ConvertTypeToTag = true); /// Emit the given number of characters as a value of type size_t. llvm::ConstantInt *getSize(CharUnits numChars); /// Set the visibility for the given LLVM GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; /// Set the TLS mode for the given LLVM GlobalValue for the thread-local /// variable declaration D. void setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const; static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { switch (V) { case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; case HiddenVisibility: return llvm::GlobalValue::HiddenVisibility; case ProtectedVisibility: return llvm::GlobalValue::ProtectedVisibility; } llvm_unreachable("unknown visibility!"); } llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) return getAddrOfCXXStructor(cast(GD.getDecl()), getFromCtorType(GD.getCtorType())); else if (isa(GD.getDecl())) return getAddrOfCXXStructor(cast(GD.getDecl()), getFromDtorType(GD.getDtorType())); else if (isa(GD.getDecl())) return GetAddrOfFunction(GD); else return GetAddrOfGlobalVar(cast(GD.getDecl())); } /// Will return a global variable of the given type. If a variable with a /// different type already exists then a new variable with the right type /// will be created and all uses of the old variable will be replaced with a /// bitcast to the new variable. llvm::GlobalVariable * CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage); llvm::Function * CreateGlobalInitOrDestructFunction(llvm::FunctionType *ty, const Twine &name, SourceLocation Loc = SourceLocation(), bool TLS = false); /// Return the address space of the underlying global variable for D, as /// determined by its declaration. Normally this is the same as the address /// space of D's type, but in CUDA, address spaces are associated with /// declarations, not types. unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace); /// Return the llvm::Constant for the address of the given global variable. /// If Ty is non-null and if the global doesn't exist, then it will be greated /// with the specified type instead of whatever the normal requested type /// would be. llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty = nullptr); /// Return the address of the given function. If Ty is non-null, then this /// function will use the specified type if it has to create it. llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = 0, bool ForVTable = false, bool DontDefer = false); /// Get the address of the RTTI descriptor for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); /// Get the address of a uuid descriptor . llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E); /// Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); /// Get a reference to the target of VD. llvm::Constant *GetWeakRefReference(const ValueDecl *VD); /// Returns the offset from a derived class to a class. Returns null if the /// offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd); /// A pair of helper functions for a __block variable. class ByrefHelpers : public llvm::FoldingSetNode { public: llvm::Constant *CopyHelper; llvm::Constant *DisposeHelper; /// The alignment of the field. This is important because /// different offsets to the field within the byref struct need to /// have different helper functions. CharUnits Alignment; ByrefHelpers(CharUnits alignment) : Alignment(alignment) {} virtual ~ByrefHelpers(); void Profile(llvm::FoldingSetNodeID &id) const { id.AddInteger(Alignment.getQuantity()); profileImpl(id); } virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0; virtual bool needsCopy() const { return true; } virtual void emitCopy(CodeGenFunction &CGF, llvm::Value *dest, llvm::Value *src) = 0; virtual bool needsDispose() const { return true; } virtual void emitDispose(CodeGenFunction &CGF, llvm::Value *field) = 0; }; llvm::FoldingSet ByrefHelpersCache; /// Fetches the global unique block count. int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; } /// Fetches the type of a generic block descriptor. llvm::Type *getBlockDescriptorType(); /// The type of a generic block literal. llvm::Type *getGenericBlockLiteralType(); /// Gets the address of a block which requires no captures. llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); /// Return a pointer to a constant CFString object for the given string. llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal); /// Return a pointer to a constant NSString object for the given string. Or a /// user defined String object as defined via /// -fconstant-string-class=class_name option. llvm::Constant *GetAddrOfConstantString(const StringLiteral *Literal); /// Return a constant array for the given string. llvm::Constant *GetConstantArrayFromStringLiteral(const StringLiteral *E); /// Return a pointer to a constant array for the given string literal. llvm::GlobalVariable * GetAddrOfConstantStringFromLiteral(const StringLiteral *S, StringRef Name = ".str"); /// Return a pointer to a constant array for the given ObjCEncodeExpr node. llvm::GlobalVariable * GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *); /// Returns a pointer to a character array containing the literal and a /// terminating '\0' character. The result has pointer to array type. /// /// \param GlobalName If provided, the name to use for the global (if one is /// created). llvm::GlobalVariable * GetAddrOfConstantCString(const std::string &Str, const char *GlobalName = nullptr, unsigned Alignment = 0); /// Returns a pointer to a constant global variable for the given file-scope /// compound literal expression. llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E); /// \brief Returns a pointer to a global variable representing a temporary /// with static or thread storage duration. llvm::Constant *GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E, const Expr *Inner); /// \brief Retrieve the record type that describes the state of an /// Objective-C fast enumeration loop (for..in). QualType getObjCFastEnumerationStateType(); // Produce code for this constructor/destructor. This method doesn't try // to apply any ABI rules about which other constructors/destructors // are needed or if they are alias to each other. llvm::Function *codegenCXXStructor(const CXXMethodDecl *MD, StructorType Type); /// Return the address of the constructor/destructor of the given type. llvm::GlobalValue * getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo = nullptr, llvm::FunctionType *FnType = nullptr, bool DontDefer = false); /// Given a builtin id for a function like "__builtin_fabsf", return a /// Function* for "fabsf". llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); llvm::Function *getIntrinsic(unsigned IID, ArrayRef Tys = None); /// Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); /// \brief Stored a deferred empty coverage mapping for an unused /// and thus uninstrumented top level declaration. void AddDeferredUnusedCoverageMapping(Decl *D); /// \brief Remove the deferred empty coverage mapping as this /// declaration is actually instrumented. void ClearUnusedCoverageMapping(const Decl *D); /// \brief Emit all the deferred coverage mappings /// for the uninstrumented functions. void EmitDeferredUnusedCoverageMappings(); /// Tell the consumer that this variable has been instantiated. void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); /// \brief If the declaration has internal linkage but is inside an /// extern "C" linkage specification, prepare to emit an alias for it /// to the expected name. template void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV); /// Add a global to a list to be added to the llvm.used metadata. void addUsedGlobal(llvm::GlobalValue *GV); /// Add a global to a list to be added to the llvm.compiler.used metadata. void addCompilerUsedGlobal(llvm::GlobalValue *GV); /// Add a destructor and object to add to the C++ global destructor function. void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object) { CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object)); } /// Create a new runtime function with the specified type and name. llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name, llvm::AttributeSet ExtraAttrs = llvm::AttributeSet()); /// Create a new compiler builtin function with the specified type and name. llvm::Constant *CreateBuiltinFunction(llvm::FunctionType *Ty, StringRef Name, llvm::AttributeSet ExtraAttrs = llvm::AttributeSet()); /// Create a new runtime global variable with the specified type and name. llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, StringRef Name); ///@name Custom Blocks Runtime Interfaces ///@{ llvm::Constant *getNSConcreteGlobalBlock(); llvm::Constant *getNSConcreteStackBlock(); llvm::Constant *getBlockObjectAssign(); llvm::Constant *getBlockObjectDispose(); ///@} llvm::Constant *getLLVMLifetimeStartFn(); llvm::Constant *getLLVMLifetimeEndFn(); // Make sure that this type is translated. void UpdateCompletedType(const TagDecl *TD); llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); /// Try to emit the initializer for the given declaration as a constant; /// returns 0 if the expression cannot be emitted as a constant. llvm::Constant *EmitConstantInit(const VarDecl &D, CodeGenFunction *CGF = nullptr); /// Try to emit the given expression as a constant; returns 0 if the /// expression cannot be emitted as a constant. llvm::Constant *EmitConstantExpr(const Expr *E, QualType DestType, CodeGenFunction *CGF = nullptr); /// Emit the given constant value as a constant, in the type's scalar /// representation. llvm::Constant *EmitConstantValue(const APValue &Value, QualType DestType, CodeGenFunction *CGF = nullptr); /// Emit the given constant value as a constant, in the type's memory /// representation. llvm::Constant *EmitConstantValueForMemory(const APValue &Value, QualType DestType, CodeGenFunction *CGF = nullptr); /// Return the result of value-initializing the given type, i.e. a null /// expression of the given type. This is usually, but not always, an LLVM /// null constant. llvm::Constant *EmitNullConstant(QualType T); /// Return a null constant appropriate for zero-initializing a base class with /// the given type. This is usually, but not always, an LLVM null constant. llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record); /// Emit a general error that something can't be done. void Error(SourceLocation loc, StringRef error); /// Print out an error that codegen doesn't support the specified stmt yet. void ErrorUnsupported(const Stmt *S, const char *Type); /// Print out an error that codegen doesn't support the specified decl yet. void ErrorUnsupported(const Decl *D, const char *Type); /// Set the attributes on the LLVM function for the given decl and function /// info. This applies attributes necessary for handling the ABI as well as /// user specified attributes like section. void SetInternalFunctionAttributes(const Decl *D, llvm::Function *F, const CGFunctionInfo &FI); /// Set the LLVM function attributes (sext, zext, etc). void SetLLVMFunctionAttributes(const Decl *D, const CGFunctionInfo &Info, llvm::Function *F); /// Set the LLVM function attributes which only apply to a function /// definition. void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F); /// Return true iff the given type uses 'sret' when used as a return type. bool ReturnTypeUsesSRet(const CGFunctionInfo &FI); /// Return true iff the given type uses an argument slot when 'sret' is used /// as a return type. bool ReturnSlotInterferesWithArgs(const CGFunctionInfo &FI); /// Return true iff the given type uses 'fpret' when used as a return type. bool ReturnTypeUsesFPRet(QualType ResultType); /// Return true iff the given type uses 'fp2ret' when used as a return type. bool ReturnTypeUsesFP2Ret(QualType ResultType); /// Get the LLVM attributes and calling convention to use for a particular /// function type. /// /// \param Info - The function type information. /// \param TargetDecl - The decl these attributes are being constructed /// for. If supplied the attributes applied to this decl may contribute to the /// function attributes and calling convention. /// \param PAL [out] - On return, the attribute list to use. /// \param CallingConv [out] - On return, the LLVM calling convention to use. void ConstructAttributeList(const CGFunctionInfo &Info, const Decl *TargetDecl, AttributeListType &PAL, unsigned &CallingConv, bool AttrOnCallSite); StringRef getMangledName(GlobalDecl GD); StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); void EmitTentativeDefinition(const VarDecl *D); void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); /// Emit the RTTI descriptors for the builtin types. void EmitFundamentalRTTIDescriptors(); /// \brief Appends Opts to the "Linker Options" metadata value. void AppendLinkerOptions(StringRef Opts); /// \brief Appends a detect mismatch command to the linker options. void AddDetectMismatch(StringRef Name, StringRef Value); /// \brief Appends a dependent lib to the "Linker Options" metadata value. void AddDependentLib(StringRef Lib); llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) { F->setLinkage(getFunctionLinkage(GD)); } /// Return the appropriate linkage for the vtable, VTT, and type information /// of the given class. llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD); /// Return the store size, in character units, of the given LLVM type. CharUnits GetTargetTypeStoreSize(llvm::Type *Ty) const; /// Returns LLVM linkage for a declarator. llvm::GlobalValue::LinkageTypes getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable); /// Returns LLVM linkage for a declarator. llvm::GlobalValue::LinkageTypes getLLVMLinkageVarDefinition(const VarDecl *VD, bool IsConstant); /// Emit all the global annotations. void EmitGlobalAnnotations(); /// Emit an annotation string. llvm::Constant *EmitAnnotationString(StringRef Str); /// Emit the annotation's translation unit. llvm::Constant *EmitAnnotationUnit(SourceLocation Loc); /// Emit the annotation line number. llvm::Constant *EmitAnnotationLineNo(SourceLocation L); /// Generate the llvm::ConstantStruct which contains the annotation /// information for a given GlobalValue. The annotation struct is /// {i8 *, i8 *, i8 *, i32}. The first field is a constant expression, the /// GlobalValue being annotated. The second field is the constant string /// created from the AnnotateAttr's annotation. The third field is a constant /// string containing the name of the translation unit. The fourth field is /// the line number in the file of the annotated value declaration. llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, SourceLocation L); /// Add global annotations that are set on D, for the global GV. Those /// annotations are emitted during finalization of the LLVM code. void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV); bool isInSanitizerBlacklist(llvm::Function *Fn, SourceLocation Loc) const; bool isInSanitizerBlacklist(llvm::GlobalVariable *GV, SourceLocation Loc, QualType Ty, StringRef Category = StringRef()) const; SanitizerMetadata *getSanitizerMetadata() { return SanitizerMD.get(); } void addDeferredVTable(const CXXRecordDecl *RD) { DeferredVTables.push_back(RD); } /// Emit code for a singal global function or var decl. Forward declarations /// are emitted lazily. void EmitGlobal(GlobalDecl D); bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target, bool InEveryTU); bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); /// Set attributes for a global definition. void setFunctionDefinitionAttributes(const FunctionDecl *D, llvm::Function *F); llvm::GlobalValue *GetGlobalValue(StringRef Ref); /// Set attributes which are common to any form of a global definition (alias, /// Objective-C method, function, global variable). /// /// NOTE: This should only be called for definitions. void SetCommonAttributes(const Decl *D, llvm::GlobalValue *GV); /// Set attributes which must be preserved by an alias. This includes common /// attributes (i.e. it includes a call to SetCommonAttributes). /// /// NOTE: This should only be called for definitions. void setAliasAttributes(const Decl *D, llvm::GlobalValue *GV); void addReplacement(StringRef Name, llvm::Constant *C); /// \brief Emit a code for threadprivate directive. /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); private: llvm::Constant * GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, bool DontDefer = false, bool IsThunk = false, llvm::AttributeSet ExtraAttrs = llvm::AttributeSet()); llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *PTy, const VarDecl *D); void setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO); /// Set function attributes for a function declaration. void SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction, bool IsThunk); void EmitGlobalDefinition(GlobalDecl D, llvm::GlobalValue *GV = nullptr); void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); // C++ related functions. void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); void CompleteDIClassType(const CXXMethodDecl* D); /// \brief Emit the function that initializes C++ thread_local variables. void EmitCXXThreadLocalInitFunc(); /// Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); /// Emit the function that destroys C++ globals. void EmitCXXGlobalDtorFunc(); /// Emit the function that initializes the specified global (if PerformInit is /// true) and registers its destructor. void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::GlobalVariable *Addr, bool PerformInit); void EmitPointerToInitFunc(const VarDecl *VD, llvm::GlobalVariable *Addr, llvm::Function *InitFunc, InitSegAttr *ISA); // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535, llvm::Constant *AssociatedData = 0); void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535); /// Generates a global array of functions and priorities using the given list /// and name. This array will have appending linkage and is suitable for use /// as a LLVM constructor or destructor array. void EmitCtorList(const CtorList &Fns, const char *GlobalName); /// Emit the RTTI descriptors for the given type. void EmitFundamentalRTTIDescriptor(QualType Type); /// Emit any needed decls for which code generation was deferred. void EmitDeferred(); /// Call replaceAllUsesWith on all pairs in Replacements. void applyReplacements(); void checkAliases(); /// Emit any vtables which we deferred and still have a use for. void EmitDeferredVTables(); /// Emit the llvm.used and llvm.compiler.used metadata. void emitLLVMUsed(); /// \brief Emit the link options introduced by imported modules. void EmitModuleLinkOptions(); /// \brief Emit aliases for internal-linkage declarations inside "C" language /// linkage specifications, giving them the "expected" name where possible. void EmitStaticExternCAliases(); void EmitDeclMetadata(); /// \brief Emit the Clang version as llvm.ident metadata. void EmitVersionIdentMetadata(); /// Emits target specific Metadata for global declarations. void EmitTargetMetadata(); /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and /// .gcda files in a way that persists in .bc files. void EmitCoverageFile(); /// Emits the initializer for a uuidof string. llvm::Constant *EmitUuidofInitializer(StringRef uuidstr); /// Determine whether the definition must be emitted; if this returns \c /// false, the definition can be emitted lazily if it's used. bool MustBeEmitted(const ValueDecl *D); /// Determine whether the definition can be emitted eagerly, or should be /// delayed until the end of the translation unit. This is relevant for /// definitions whose linkage can change, e.g. implicit function instantions /// which may later be explicitly instantiated. bool MayBeEmittedEagerly(const ValueDecl *D); /// Check whether we can use a "simpler", more core exceptions personality /// function. void SimplifyPersonality(); }; } // end namespace CodeGen } // end namespace clang #endif Index: vendor/clang/dist/lib/Driver/Tools.cpp =================================================================== --- vendor/clang/dist/lib/Driver/Tools.cpp (revision 278753) +++ vendor/clang/dist/lib/Driver/Tools.cpp (revision 278754) @@ -1,8374 +1,8375 @@ //===--- Tools.cpp - Tools Implementations --------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Tools.h" #include "InputInfo.h" #include "ToolChains.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Job.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Compression.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; static void addAssemblerKPIC(const ArgList &Args, ArgStringList &CmdArgs) { Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); if (!LastPICArg) return; if (LastPICArg->getOption().matches(options::OPT_fPIC) || LastPICArg->getOption().matches(options::OPT_fpic) || LastPICArg->getOption().matches(options::OPT_fPIE) || LastPICArg->getOption().matches(options::OPT_fpie)) { CmdArgs.push_back("-KPIC"); } } /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) { if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { D.Diag(diag::err_drv_argument_only_allowed_with) << A->getBaseArg().getAsString(Args) << (D.IsCLMode() ? "/E, /P or /EP" : "-E"); } } } /// CheckCodeGenerationOptions - Perform some validation of code generation /// arguments that is shared with gcc. static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { // In gcc, only ARM checks this, but it seems reasonable to check universally. if (Args.hasArg(options::OPT_static)) if (const Arg *A = Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-static"; } // Add backslashes to escape spaces and other backslashes. // This is used for the space-separated argument list specified with // the -dwarf-debug-flags option. static void EscapeSpacesAndBackslashes(const char *Arg, SmallVectorImpl &Res) { for ( ; *Arg; ++Arg) { switch (*Arg) { default: break; case ' ': case '\\': Res.push_back('\\'); break; } Res.push_back(*Arg); } } // Quote target names for inclusion in GNU Make dependency files. // Only the characters '$', '#', ' ', '\t' are quoted. static void QuoteTarget(StringRef Target, SmallVectorImpl &Res) { for (unsigned i = 0, e = Target.size(); i != e; ++i) { switch (Target[i]) { case ' ': case '\t': // Escape the preceding backslashes for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) Res.push_back('\\'); // Escape the space/tab Res.push_back('\\'); break; case '$': Res.push_back('$'); break; case '#': Res.push_back('\\'); break; default: break; } Res.push_back(Target[i]); } } static void addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, const char *ArgName, const char *EnvVar) { const char *DirList = ::getenv(EnvVar); bool CombinedArg = false; if (!DirList) return; // Nothing to do. StringRef Name(ArgName); if (Name.equals("-I") || Name.equals("-L")) CombinedArg = true; StringRef Dirs(DirList); if (Dirs.empty()) // Empty string should not add '.'. return; StringRef::size_type Delim; while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { if (Delim == 0) { // Leading colon. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } } else { if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); } } Dirs = Dirs.substr(Delim + 1); } if (Dirs.empty()) { // Trailing colon. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back("."); } } else { // Add the last path. if (CombinedArg) { CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); } else { CmdArgs.push_back(ArgName); CmdArgs.push_back(Args.MakeArgString(Dirs)); } } } static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs) { const Driver &D = TC.getDriver(); // Add extra linker input arguments which are not treated as inputs // (constructed via -Xarch_). Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); for (const auto &II : Inputs) { if (!TC.HasNativeLLVMSupport()) { // Don't try to pass LLVM inputs unless we have native support. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); } // Add filenames immediately. if (II.isFilename()) { CmdArgs.push_back(II.getFilename()); continue; } // Otherwise, this is a linker input argument. const Arg &A = II.getInputArg(); // Handle reserved library options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) TC.AddCXXStdlibLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) TC.AddCCKextLibArgs(Args, CmdArgs); else if (A.getOption().matches(options::OPT_z)) { // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } } // LIBRARY_PATH - included following the user specified library paths. // and only supported on native toolchains. if (!TC.isCrossCompiling()) addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); } /// \brief Determine whether Objective-C automated reference counting is /// enabled. static bool isObjCAutoRefCount(const ArgList &Args) { return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); } /// \brief Determine whether we are linking the ObjC runtime. static bool isObjCRuntimeLinked(const ArgList &Args) { if (isObjCAutoRefCount(Args)) { Args.ClaimAllArgs(options::OPT_fobjc_link_runtime); return true; } return Args.hasArg(options::OPT_fobjc_link_runtime); } static bool forwardToGCC(const Option &O) { // Don't forward inputs from the original command line. They are added from // InputInfoList. return O.getKind() != Option::InputClass && !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs) const { Arg *A; CheckPreprocessingOptions(D, Args); Args.AddLastArg(CmdArgs, options::OPT_C); Args.AddLastArg(CmdArgs, options::OPT_CC); // Handle dependency file generation. if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) || (A = Args.getLastArg(options::OPT_MD)) || (A = Args.getLastArg(options::OPT_MMD))) { // Determine the output location. const char *DepFile; if (Arg *MF = Args.getLastArg(options::OPT_MF)) { DepFile = MF->getValue(); C.addFailureResultFile(DepFile, &JA); } else if (Output.getType() == types::TY_Dependencies) { DepFile = Output.getFilename(); } else if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MM)) { DepFile = "-"; } else { DepFile = getDependencyFileName(Args, Inputs); C.addFailureResultFile(DepFile, &JA); } CmdArgs.push_back("-dependency-file"); CmdArgs.push_back(DepFile); // Add a default target if one wasn't specified. if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { const char *DepTarget; // If user provided -o, that is the dependency target, except // when we are only generating a dependency file. Arg *OutputOpt = Args.getLastArg(options::OPT_o); if (OutputOpt && Output.getType() != types::TY_Dependencies) { DepTarget = OutputOpt->getValue(); } else { // Otherwise derive from the base input. // // FIXME: This should use the computed output file location. SmallString<128> P(Inputs[0].getBaseInput()); llvm::sys::path::replace_extension(P, "o"); DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); } CmdArgs.push_back("-MT"); SmallString<128> Quoted; QuoteTarget(DepTarget, Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MD)) CmdArgs.push_back("-sys-header-deps"); if (isa(JA)) CmdArgs.push_back("-module-file-deps"); } if (Args.hasArg(options::OPT_MG)) { if (!A || A->getOption().matches(options::OPT_MD) || A->getOption().matches(options::OPT_MMD)) D.Diag(diag::err_drv_mg_requires_m_or_mm); CmdArgs.push_back("-MG"); } Args.AddLastArg(CmdArgs, options::OPT_MP); // Convert all -MQ args to -MT for (arg_iterator it = Args.filtered_begin(options::OPT_MT, options::OPT_MQ), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); if (A->getOption().matches(options::OPT_MQ)) { CmdArgs.push_back("-MT"); SmallString<128> Quoted; QuoteTarget(A->getValue(), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); // -MT flag - no change } else { A->render(Args, CmdArgs); } } // Add -i* options, and automatically translate to // -include-pch/-include-pth for transparent PCH support. It's // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. bool RenderedImplicitInclude = false; for (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = it; if (A->getOption().matches(options::OPT_include)) { bool IsFirstImplicitInclude = !RenderedImplicitInclude; RenderedImplicitInclude = true; // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; bool FoundPTH = false; bool FoundPCH = false; SmallString<128> P(A->getValue()); // We want the files to have a name like foo.h.pch. Add a dummy extension // so that replace_extension does the right thing. P += ".dummy"; if (UsePCH) { llvm::sys::path::replace_extension(P, "pch"); if (llvm::sys::fs::exists(P.str())) FoundPCH = true; } if (!FoundPCH) { llvm::sys::path::replace_extension(P, "pth"); if (llvm::sys::fs::exists(P.str())) FoundPTH = true; } if (!FoundPCH && !FoundPTH) { llvm::sys::path::replace_extension(P, "gch"); if (llvm::sys::fs::exists(P.str())) { FoundPCH = UsePCH; FoundPTH = !UsePCH; } } if (FoundPCH || FoundPTH) { if (IsFirstImplicitInclude) { A->claim(); if (UsePCH) CmdArgs.push_back("-include-pch"); else CmdArgs.push_back("-include-pth"); CmdArgs.push_back(Args.MakeArgString(P.str())); continue; } else { // Ignore the PCH if not first on command line and emit warning. D.Diag(diag::warn_drv_pch_not_first_include) << P.str() << A->getAsString(Args); } } } // Not translated, render as usual. A->claim(); A->render(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F, options::OPT_index_header_map); // Add -Wp, and -Xassembler if using the preprocessor. // FIXME: There is a very unfortunate problem here, some troubled // souls abuse -Wp, to pass preprocessor options in gcc syntax. To // really support that we would have to parse and then translate // those options. :( Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, options::OPT_Xpreprocessor); // -I- is a deprecated GCC feature, reject it. if (Arg *A = Args.getLastArg(options::OPT_I_)) D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); // If we have a --sysroot, and don't have an explicit -isysroot flag, add an // -isysroot to the CC1 invocation. StringRef sysroot = C.getSysRoot(); if (sysroot != "") { if (!Args.hasArg(options::OPT_isysroot)) { CmdArgs.push_back("-isysroot"); CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } } // Parse additional include paths from environment variables. // FIXME: We should probably sink the logic for handling these from the // frontend into the driver. It will allow deleting 4 otherwise unused flags. // CPATH - included following the user specified includes (but prior to // builtin and standard includes). addDirectoryList(Args, CmdArgs, "-I", "CPATH"); // C_INCLUDE_PATH - system includes enabled when compiling C. addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH"); // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH"); // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH"); // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH"); // Add C++ include arguments, if needed. if (types::isCXX(Inputs[0].getType())) getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs); // Add system include arguments. getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs); } // FIXME: Move to target hook. static bool isSignedCharDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { default: return true; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: if (Triple.isOSDarwin() || Triple.isOSWindows()) return true; return false; case llvm::Triple::ppc: case llvm::Triple::ppc64: if (Triple.isOSDarwin()) return true; return false; case llvm::Triple::ppc64le: case llvm::Triple::systemz: case llvm::Triple::xcore: return false; } } static bool isNoCommonDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { default: return false; case llvm::Triple::xcore: return true; } } // Handle -mhwdiv=. static void getARMHWDivFeatures(const Driver &D, const Arg *A, const ArgList &Args, std::vector &Features) { StringRef HWDiv = A->getValue(); if (HWDiv == "arm") { Features.push_back("+hwdiv-arm"); Features.push_back("-hwdiv"); } else if (HWDiv == "thumb") { Features.push_back("-hwdiv-arm"); Features.push_back("+hwdiv"); } else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") { Features.push_back("+hwdiv-arm"); Features.push_back("+hwdiv"); } else if (HWDiv == "none") { Features.push_back("-hwdiv-arm"); Features.push_back("-hwdiv"); } else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } // Handle -mfpu=. // // FIXME: Centralize feature selection, defaulting shouldn't be also in the // frontend target. static void getARMFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args, std::vector &Features) { StringRef FPU = A->getValue(); // Set the target features based on the FPU. if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { // Disable any default FPU support. Features.push_back("-vfp2"); Features.push_back("-vfp3"); Features.push_back("-neon"); } else if (FPU == "vfp") { Features.push_back("+vfp2"); Features.push_back("-neon"); } else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") { Features.push_back("+vfp3"); Features.push_back("+d16"); Features.push_back("-neon"); } else if (FPU == "vfp3" || FPU == "vfpv3") { Features.push_back("+vfp3"); Features.push_back("-neon"); } else if (FPU == "vfp4-d16" || FPU == "vfpv4-d16") { Features.push_back("+vfp4"); Features.push_back("+d16"); Features.push_back("-neon"); } else if (FPU == "vfp4" || FPU == "vfpv4") { Features.push_back("+vfp4"); Features.push_back("-neon"); } else if (FPU == "fp4-sp-d16" || FPU == "fpv4-sp-d16") { Features.push_back("+vfp4"); Features.push_back("+d16"); Features.push_back("+fp-only-sp"); Features.push_back("-neon"); } else if (FPU == "fp5-sp-d16" || FPU == "fpv5-sp-d16") { Features.push_back("+fp-armv8"); Features.push_back("+fp-only-sp"); Features.push_back("+d16"); Features.push_back("-neon"); Features.push_back("-crypto"); } else if (FPU == "fp5-dp-d16" || FPU == "fpv5-dp-d16" || FPU == "fp5-d16" || FPU == "fpv5-d16") { Features.push_back("+fp-armv8"); Features.push_back("+d16"); Features.push_back("-neon"); Features.push_back("-crypto"); } else if (FPU == "fp-armv8") { Features.push_back("+fp-armv8"); Features.push_back("-neon"); Features.push_back("-crypto"); } else if (FPU == "neon-fp-armv8") { Features.push_back("+fp-armv8"); Features.push_back("+neon"); Features.push_back("-crypto"); } else if (FPU == "crypto-neon-fp-armv8") { Features.push_back("+fp-armv8"); Features.push_back("+neon"); Features.push_back("+crypto"); } else if (FPU == "neon") { Features.push_back("+neon"); } else if (FPU == "neon-vfpv3") { Features.push_back("+vfp3"); Features.push_back("+neon"); } else if (FPU == "neon-vfpv4") { Features.push_back("+neon"); Features.push_back("+vfp4"); } else if (FPU == "none") { Features.push_back("-vfp2"); Features.push_back("-vfp3"); Features.push_back("-vfp4"); Features.push_back("-fp-armv8"); Features.push_back("-crypto"); Features.push_back("-neon"); } else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args, const llvm::Triple &Triple) { StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; else { FloatABI = A->getValue(); if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "soft"; } } } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { switch (Triple.getOS()) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: { // Darwin defaults to "softfp" for v6 and v7. // // FIXME: Factor out an ARM class so we can cache the arch somewhere. std::string ArchName = arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple)); if (StringRef(ArchName).startswith("v6") || StringRef(ArchName).startswith("v7")) FloatABI = "softfp"; else FloatABI = "soft"; break; } // FIXME: this is invalid for WindowsCE case llvm::Triple::Win32: FloatABI = "hard"; break; case llvm::Triple::FreeBSD: switch(Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: FloatABI = "hard"; break; default: // FreeBSD defaults to soft float FloatABI = "soft"; break; } break; default: switch(Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: FloatABI = "hard"; break; case llvm::Triple::GNUEABI: FloatABI = "softfp"; break; case llvm::Triple::EABIHF: FloatABI = "hard"; break; case llvm::Triple::EABI: // EABI is always AAPCS, and if it was not marked 'hard', it's softfp FloatABI = "softfp"; break; case llvm::Triple::Android: { std::string ArchName = arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple)); if (StringRef(ArchName).startswith("v7")) FloatABI = "softfp"; else FloatABI = "soft"; break; } default: // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; if (Triple.getOS() != llvm::Triple::UnknownOS || !Triple.isOSBinFormatMachO()) D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; break; } } } return FloatABI; } static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features, bool ForAS) { StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); if (!ForAS) { // FIXME: Note, this is a hack, the LLVM backend doesn't actually use these // yet (it uses the -mfloat-abi and -msoft-float options), and it is // stripped out by the ARM target. We should probably pass this a new // -target-option, which is handled by the -cc1/-cc1as invocation. // // FIXME2: For consistency, it would be ideal if we set up the target // machine state the same when using the frontend or the assembler. We don't // currently do that for the assembler, we pass the options directly to the // backend and never even instantiate the frontend TargetInfo. If we did, // and used its handleTargetFeatures hook, then we could ensure the // assembler and the frontend behave the same. // Use software floating point operations? if (FloatABI == "soft") Features.push_back("+soft-float"); // Use software floating point argument passing? if (FloatABI != "hard") Features.push_back("+soft-float-abi"); } // Honor -mfpu=. if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) getARMFPUFeatures(D, A, Args, Features); if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ)) getARMHWDivFeatures(D, A, Args, Features); // Setting -msoft-float effectively disables NEON because of the GCC // implementation, although the same isn't true of VFP or VFP3. if (FloatABI == "soft") { Features.push_back("-neon"); // Also need to explicitly disable features which imply NEON. Features.push_back("-crypto"); } // En/disable crc if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { if (A->getOption().matches(options::OPT_mcrc)) Features.push_back("+crc"); else Features.push_back("-crc"); } } void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { const Driver &D = getToolChain().getDriver(); // Get the effective triple, which takes into account the deployment target. std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); llvm::Triple Triple(TripleStr); std::string CPUName = arm::getARMTargetCPU(Args, Triple); // Select the ABI to use. // // FIXME: Support -meabi. // FIXME: Parts of this are duplicated in the backend, unify this somehow. const char *ABIName = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); } else if (Triple.isOSBinFormatMachO()) { // The backend is hardwired to assume AAPCS for M-class processors, ensure // the frontend matches that. if (Triple.getEnvironment() == llvm::Triple::EABI || Triple.getOS() == llvm::Triple::UnknownOS || StringRef(CPUName).startswith("cortex-m")) { ABIName = "aapcs"; } else { ABIName = "apcs-gnu"; } } else if (Triple.isOSWindows()) { // FIXME: this is invalid for WindowsCE ABIName = "aapcs"; } else { // Select the default based on the platform. switch(Triple.getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: ABIName = "aapcs-linux"; break; case llvm::Triple::EABIHF: case llvm::Triple::EABI: ABIName = "aapcs"; break; default: if (Triple.getOS() == llvm::Triple::NetBSD) ABIName = "apcs-gnu"; else ABIName = "aapcs"; break; } } CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); // Determine floating point ABI from the options & target defaults. StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); if (FloatABI == "soft") { // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else if (FloatABI == "softfp") { // Floating point operations are hard, but argument passing is soft. CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } // Kernel code has more strict alignment requirements. if (KernelOrKext) { if (!Triple.isiOS() || Triple.isOSVersionLT(6)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-long-calls"); } CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-strict-align"); // The kext linker doesn't know how to deal with movw/movt. CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-use-movt=0"); } // -mkernel implies -mstrict-align; don't add the redundant option. if (!KernelOrKext) { if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { CmdArgs.push_back("-backend-option"); if (A->getOption().matches(options::OPT_mno_unaligned_access)) CmdArgs.push_back("-arm-strict-align"); else { if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) D.Diag(diag::err_target_unsupported_unaligned) << "v6m"; CmdArgs.push_back("-arm-no-strict-align"); } } } // Setting -mno-global-merge disables the codegen global merge pass. Setting // -mglobal-merge has no effect as the pass is enabled by default. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-mno-global-merge"); } if (!Args.hasFlag(options::OPT_mimplicit_float, options::OPT_mno_implicit_float, true)) CmdArgs.push_back("-no-implicit-float"); // llvm does not support reserving registers in general. There is support // for reserving r9 on ARM though (defined as a platform-specific register // in ARM EABI). if (Args.hasArg(options::OPT_ffixed_r9)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-reserve-r9"); } } /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are /// targeting. static std::string getAArch64TargetCPU(const ArgList &Args) { Arg *A; std::string CPU; // If we have -mtune or -mcpu, use that. if ((A = Args.getLastArg(options::OPT_mtune_EQ))) { CPU = A->getValue(); } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); CPU = Mcpu.split("+").first; } // Handle CPU name is 'native'. if (CPU == "native") return llvm::sys::getHostCPUName(); else if (CPU.size()) return CPU; // Make sure we pick "cyclone" if -arch is used. // FIXME: Should this be picked by checking the target triple instead? if (Args.getLastArg(options::OPT_arch)) return "cyclone"; return "generic"; } void Clang::AddAArch64TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); llvm::Triple Triple(TripleStr); if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("-disable-red-zone"); if (!Args.hasFlag(options::OPT_mimplicit_float, options::OPT_mno_implicit_float, true)) CmdArgs.push_back("-no-implicit-float"); const char *ABIName = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) ABIName = A->getValue(); else if (Triple.isOSDarwin()) ABIName = "darwinpcs"; else ABIName = "aapcs"; CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { CmdArgs.push_back("-backend-option"); if (A->getOption().matches(options::OPT_mno_unaligned_access)) CmdArgs.push_back("-aarch64-strict-align"); else CmdArgs.push_back("-aarch64-no-strict-align"); } if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, options::OPT_mno_fix_cortex_a53_835769)) { CmdArgs.push_back("-backend-option"); if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); else CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); } else if (Triple.getEnvironment() == llvm::Triple::Android) { // Enabled A53 errata (835769) workaround by default on android CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); } // Setting -mno-global-merge disables the codegen global merge pass. Setting // -mglobal-merge has no effect as the pass is enabled by default. if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, options::OPT_mno_global_merge)) { if (A->getOption().matches(options::OPT_mno_global_merge)) CmdArgs.push_back("-mno-global-merge"); } if (Args.hasArg(options::OPT_ffixed_x18)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-aarch64-reserve-x18"); } } // Get CPU and ABI names. They are not independent // so we have to calculate them together. void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, StringRef &CPUName, StringRef &ABIName) { const char *DefMips32CPU = "mips32r2"; const char *DefMips64CPU = "mips64r2"; // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the // default for mips64(el)?-img-linux-gnu. if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && Triple.getEnvironment() == llvm::Triple::GNU) { DefMips32CPU = "mips32r6"; DefMips64CPU = "mips64r6"; } // MIPS3 is the default for mips64*-unknown-openbsd. if (Triple.getOS() == llvm::Triple::OpenBSD) DefMips64CPU = "mips3"; if (Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ)) CPUName = A->getValue(); if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); // Convert a GNU style Mips ABI name to the name // accepted by LLVM Mips backend. ABIName = llvm::StringSwitch(ABIName) .Case("32", "o32") .Case("64", "n64") .Default(ABIName); } // Setup default CPU and ABI names. if (CPUName.empty() && ABIName.empty()) { switch (Triple.getArch()) { default: llvm_unreachable("Unexpected triple arch name"); case llvm::Triple::mips: case llvm::Triple::mipsel: CPUName = DefMips32CPU; break; case llvm::Triple::mips64: case llvm::Triple::mips64el: CPUName = DefMips64CPU; break; } } if (ABIName.empty()) { // Deduce ABI name from the target triple. if (Triple.getArch() == llvm::Triple::mips || Triple.getArch() == llvm::Triple::mipsel) ABIName = "o32"; else ABIName = "n64"; } if (CPUName.empty()) { // Deduce CPU name from ABI name. CPUName = llvm::StringSwitch(ABIName) .Cases("o32", "eabi", DefMips32CPU) .Cases("n32", "n64", DefMips64CPU) .Default(""); } // FIXME: Warn on inconsistent use of -march and -mabi. } // Convert ABI name to the GNU tools acceptable variant. static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { return llvm::StringSwitch(ABI) .Case("o32", "32") .Case("n64", "64") .Default(ABI); } // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, // and -mfloat-abi=. static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, options::OPT_mfloat_abi_EQ)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; else { FloatABI = A->getValue(); if (FloatABI != "soft" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "hard"; } } } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { // Assume "hard", because it's a default value used by gcc. // When we start to recognize specific target MIPS processors, // we will be able to select the default more correctly. FloatABI = "hard"; } return FloatABI; } static void AddTargetFeature(const ArgList &Args, std::vector &Features, OptSpecifier OnOpt, OptSpecifier OffOpt, StringRef FeatureName) { if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { if (A->getOption().matches(OnOpt)) Features.push_back(Args.MakeArgString("+" + FeatureName)); else Features.push_back(Args.MakeArgString("-" + FeatureName)); } } static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); ABIName = getGnuCompatibleMipsABIName(ABIName); // Always override the backend's default ABI. std::string ABIFeature = llvm::StringSwitch(ABIName) .Case("32", "+o32") .Case("n32", "+n32") .Case("64", "+n64") .Case("eabi", "+eabi") .Default(("+" + ABIName).str()); Features.push_back("-o32"); Features.push_back("-n64"); Features.push_back(Args.MakeArgString(ABIFeature)); AddTargetFeature(Args, Features, options::OPT_mno_abicalls, options::OPT_mabicalls, "noabicalls"); StringRef FloatABI = getMipsFloatABI(D, Args); if (FloatABI == "soft") { // FIXME: Note, this is a hack. We need to pass the selected float // mode to the MipsTargetInfoBase to define appropriate macros there. // Now it is the only method. Features.push_back("+soft-float"); } if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { StringRef Val = StringRef(A->getValue()); if (Val == "2008") Features.push_back("+nan2008"); else if (Val == "legacy") Features.push_back("-nan2008"); else D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } AddTargetFeature(Args, Features, options::OPT_msingle_float, options::OPT_mdouble_float, "single-float"); AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, "mips16"); AddTargetFeature(Args, Features, options::OPT_mmicromips, options::OPT_mno_micromips, "micromips"); AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp, "dsp"); AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2, "dspr2"); AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa, "msa"); // Add the last -mfp32/-mfpxx/-mfp64 or if none are given and the ABI is O32 // pass -mfpxx if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, options::OPT_mfp64)) { if (A->getOption().matches(options::OPT_mfp32)) Features.push_back(Args.MakeArgString("-fp64")); else if (A->getOption().matches(options::OPT_mfpxx)) { Features.push_back(Args.MakeArgString("+fpxx")); Features.push_back(Args.MakeArgString("+nooddspreg")); } else Features.push_back(Args.MakeArgString("+fp64")); } else if (mips::isFPXXDefault(Triple, CPUName, ABIName)) { Features.push_back(Args.MakeArgString("+fpxx")); Features.push_back(Args.MakeArgString("+nooddspreg")); } AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, options::OPT_modd_spreg, "nooddspreg"); } void Clang::AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); StringRef CPUName; StringRef ABIName; const llvm::Triple &Triple = getToolChain().getTriple(); mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName.data()); StringRef FloatABI = getMipsFloatABI(D, Args); if (FloatABI == "soft") { // Floating point operations and argument passing are soft. CmdArgs.push_back("-msoft-float"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mfloat-abi"); CmdArgs.push_back("hard"); } if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) { if (A->getOption().matches(options::OPT_mxgot)) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-mxgot"); } } if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1, options::OPT_mno_ldc1_sdc1)) { if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-mno-ldc1-sdc1"); } } if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division, options::OPT_mno_check_zero_division)) { if (A->getOption().matches(options::OPT_mno_check_zero_division)) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-mno-check-zero-division"); } } if (Arg *A = Args.getLastArg(options::OPT_G)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); A->claim(); } } /// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. static std::string getPPCTargetCPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { StringRef CPUName = A->getValue(); if (CPUName == "native") { std::string CPU = llvm::sys::getHostCPUName(); if (!CPU.empty() && CPU != "generic") return CPU; else return ""; } return llvm::StringSwitch(CPUName) .Case("common", "generic") .Case("440", "440") .Case("440fp", "440") .Case("450", "450") .Case("601", "601") .Case("602", "602") .Case("603", "603") .Case("603e", "603e") .Case("603ev", "603ev") .Case("604", "604") .Case("604e", "604e") .Case("620", "620") .Case("630", "pwr3") .Case("G3", "g3") .Case("7400", "7400") .Case("G4", "g4") .Case("7450", "7450") .Case("G4+", "g4+") .Case("750", "750") .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") .Case("a2q", "a2q") .Case("e500mc", "e500mc") .Case("e5500", "e5500") .Case("power3", "pwr3") .Case("power4", "pwr4") .Case("power5", "pwr5") .Case("power5x", "pwr5x") .Case("power6", "pwr6") .Case("power6x", "pwr6x") .Case("power7", "pwr7") .Case("power8", "pwr8") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") .Case("pwr5", "pwr5") .Case("pwr5x", "pwr5x") .Case("pwr6", "pwr6") .Case("pwr6x", "pwr6x") .Case("pwr7", "pwr7") .Case("pwr8", "pwr8") .Case("powerpc", "ppc") .Case("powerpc64", "ppc64") .Case("powerpc64le", "ppc64le") .Default(""); } return ""; } static void getPPCTargetFeatures(const ArgList &Args, std::vector &Features) { for (arg_iterator it = Args.filtered_begin(options::OPT_m_ppc_Features_Group), ie = Args.filtered_end(); it != ie; ++it) { StringRef Name = (*it)->getOption().getName(); (*it)->claim(); // Skip over "-m". assert(Name.startswith("m") && "Invalid feature name."); Name = Name.substr(1); bool IsNegative = Name.startswith("no-"); if (IsNegative) Name = Name.substr(3); // Note that gcc calls this mfcrf and LLVM calls this mfocrf so we // pass the correct option to the backend while calling the frontend // option the same. // TODO: Change the LLVM backend option maybe? if (Name == "mfcrf") Name = "mfocrf"; Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } // Altivec is a bit weird, allow overriding of the Altivec feature here. AddTargetFeature(Args, Features, options::OPT_faltivec, options::OPT_fno_altivec, "altivec"); } void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. const char *ABIName = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); } else if (getToolChain().getTriple().isOSLinux()) switch(getToolChain().getArch()) { case llvm::Triple::ppc64: ABIName = "elfv1"; break; case llvm::Triple::ppc64le: ABIName = "elfv2"; break; default: break; } if (ABIName) { CmdArgs.push_back("-target-abi"); CmdArgs.push_back(ABIName); } } bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef(Value)); } /// Get the (LLVM) name of the R600 gpu we are targeting. static std::string getR600TargetGPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { const char *GPUName = A->getValue(); return llvm::StringSwitch(GPUName) .Cases("rv630", "rv635", "r600") .Cases("rv610", "rv620", "rs780", "rs880") .Case("rv740", "rv770") .Case("palm", "cedar") .Cases("sumo", "sumo2", "sumo") .Case("hemlock", "cypress") .Case("aruba", "cayman") .Default(GPUName); } return ""; } static void getSparcTargetFeatures(const ArgList &Args, std::vector &Features) { bool SoftFloatABI = true; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_mhard_float)) SoftFloatABI = false; } if (SoftFloatABI) Features.push_back("+soft-float"); } void Clang::AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); // Select the float ABI as determined by -msoft-float and -mhard-float. StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) { if (A->getOption().matches(options::OPT_msoft_float)) FloatABI = "soft"; else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; } // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { // Assume "soft", but warn the user we are guessing. FloatABI = "soft"; D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft"; } if (FloatABI == "soft") { // Floating point operations and argument passing are soft. // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); } else { assert(FloatABI == "hard" && "Invalid float abi!"); CmdArgs.push_back("-mhard-float"); } } static const char *getSystemZTargetCPU(const ArgList &Args) { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) return A->getValue(); return "z10"; } static const char *getX86TargetCPU(const ArgList &Args, const llvm::Triple &Triple) { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { if (StringRef(A->getValue()) != "native") { if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h") return "core-avx2"; return A->getValue(); } // FIXME: Reject attempts to use -march=native unless the target matches // the host. // // FIXME: We should also incorporate the detected target features for use // with -native. std::string CPU = llvm::sys::getHostCPUName(); if (!CPU.empty() && CPU != "generic") return Args.MakeArgString(CPU); } // Select the default CPU if none was given (or detection failed). if (Triple.getArch() != llvm::Triple::x86_64 && Triple.getArch() != llvm::Triple::x86) return nullptr; // This routine is only handling x86 targets. bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; // FIXME: Need target hooks. if (Triple.isOSDarwin()) { if (Triple.getArchName() == "x86_64h") return "core-avx2"; return Is64Bit ? "core2" : "yonah"; } // On Android use targets compatible with gcc if (Triple.getEnvironment() == llvm::Triple::Android) return Is64Bit ? "x86-64" : "i686"; // Everything else goes to x86-64 in 64-bit mode. if (Is64Bit) return "x86-64"; switch (Triple.getOS()) { case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: return "i486"; case llvm::Triple::Haiku: return "i586"; case llvm::Triple::Bitrig: return "i686"; default: // Fallback to p4. return "pentium4"; } } static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { switch(T.getArch()) { default: return ""; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: return getAArch64TargetCPU(Args); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: return arm::getARMTargetCPU(Args, T); case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); return CPUName; } case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: { std::string TargetCPUName = getPPCTargetCPU(Args); // LLVM may default to generating code for the native CPU, // but, like gcc, we default to a more generic option for // each architecture. (except on Darwin) if (TargetCPUName.empty() && !T.isOSDarwin()) { if (T.getArch() == llvm::Triple::ppc64) TargetCPUName = "ppc64"; else if (T.getArch() == llvm::Triple::ppc64le) TargetCPUName = "ppc64le"; else TargetCPUName = "ppc"; } return TargetCPUName; } case llvm::Triple::sparc: case llvm::Triple::sparcv9: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; case llvm::Triple::x86: case llvm::Triple::x86_64: return getX86TargetCPU(Args, T); case llvm::Triple::hexagon: return "hexagon" + toolchains::Hexagon_TC::GetTargetCPU(Args).str(); case llvm::Triple::systemz: return getSystemZTargetCPU(Args); case llvm::Triple::r600: case llvm::Triple::amdgcn: return getR600TargetGPU(Args); } } static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { // Tell the linker to load the plugin. This has to come before AddLinkerInputs // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. CmdArgs.push_back("-plugin"); - std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so"; + std::string Plugin = ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so"; CmdArgs.push_back(Args.MakeArgString(Plugin)); // Try to pass driver level flags relevant to LTO code generation down to // the plugin. // Handle flags for selecting CPU variants. std::string CPU = getCPUName(Args, ToolChain.getTriple()); if (!CPU.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); } static void getX86TargetFeatures(const Driver & D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features) { if (Triple.getArchName() == "x86_64h") { // x86_64h implies quite a few of the more modern subtarget features // for Haswell class CPUs, but not all of them. Opt-out of a few. Features.push_back("-rdrnd"); Features.push_back("-aes"); Features.push_back("-pclmul"); Features.push_back("-rtm"); Features.push_back("-hle"); Features.push_back("-fsgsbase"); } // Add features to comply with gcc on Android if (Triple.getEnvironment() == llvm::Triple::Android) { if (Triple.getArch() == llvm::Triple::x86_64) { Features.push_back("+sse4.2"); Features.push_back("+popcnt"); } else Features.push_back("+ssse3"); } // Set features according to the -arch flag on MSVC if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) { StringRef Arch = A->getValue(); bool ArchUsed = false; // First, look for flags that are shared in x86 and x86-64. if (Triple.getArch() == llvm::Triple::x86_64 || Triple.getArch() == llvm::Triple::x86) { if (Arch == "AVX" || Arch == "AVX2") { ArchUsed = true; Features.push_back(Args.MakeArgString("+" + Arch.lower())); } } // Then, look for x86-specific flags. if (Triple.getArch() == llvm::Triple::x86) { if (Arch == "IA32") { ArchUsed = true; } else if (Arch == "SSE" || Arch == "SSE2") { ArchUsed = true; Features.push_back(Args.MakeArgString("+" + Arch.lower())); } } if (!ArchUsed) D.Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(Args); } // Now add any that the user explicitly requested on the command line, // which may override the defaults. for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group), ie = Args.filtered_end(); it != ie; ++it) { StringRef Name = (*it)->getOption().getName(); (*it)->claim(); // Skip over "-m". assert(Name.startswith("m") && "Invalid feature name."); Name = Name.substr(1); bool IsNegative = Name.startswith("no-"); if (IsNegative) Name = Name.substr(3); Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } } void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("-disable-red-zone"); // Default to avoid implicit floating-point for kernel/kext code, but allow // that to be overridden with -mno-soft-float. bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)); if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_soft_float, options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) { const Option &O = A->getOption(); NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || O.matches(options::OPT_msoft_float)); } if (NoImplicitFloat) CmdArgs.push_back("-no-implicit-float"); if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { StringRef Value = A->getValue(); if (Value == "intel" || Value == "att") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } } } static inline bool HasPICArg(const ArgList &Args) { return Args.hasArg(options::OPT_fPIC) || Args.hasArg(options::OPT_fpic); } static Arg *GetLastSmallDataThresholdArg(const ArgList &Args) { return Args.getLastArg(options::OPT_G, options::OPT_G_EQ, options::OPT_msmall_data_threshold_EQ); } static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) { std::string value; if (HasPICArg(Args)) value = "0"; else if (Arg *A = GetLastSmallDataThresholdArg(Args)) { value = A->getValue(); A->claim(); } return value; } void Clang::AddHexagonTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-fno-signed-char"); CmdArgs.push_back("-mqdsp6-compat"); CmdArgs.push_back("-Wreturn-type"); std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); if (!SmallDataThreshold.empty()) { CmdArgs.push_back ("-mllvm"); CmdArgs.push_back(Args.MakeArgString( "-hexagon-small-data-threshold=" + SmallDataThreshold)); } if (!Args.hasArg(options::OPT_fno_short_enums)) CmdArgs.push_back("-fshort-enums"); if (Args.getLastArg(options::OPT_mieee_rnd_near)) { CmdArgs.push_back ("-mllvm"); CmdArgs.push_back ("-enable-hexagon-ieee-rnd-near"); } CmdArgs.push_back ("-mllvm"); CmdArgs.push_back ("-machine-sink-split=0"); } // Decode AArch64 features from string like +[no]featureA+[no]featureB+... static bool DecodeAArch64Features(const Driver &D, StringRef text, std::vector &Features) { SmallVector Split; text.split(Split, StringRef("+"), -1, false); for (unsigned I = 0, E = Split.size(); I != E; ++I) { const char *result = llvm::StringSwitch(Split[I]) .Case("fp", "+fp-armv8") .Case("simd", "+neon") .Case("crc", "+crc") .Case("crypto", "+crypto") .Case("nofp", "-fp-armv8") .Case("nosimd", "-neon") .Case("nocrc", "-crc") .Case("nocrypto", "-crypto") .Default(nullptr); if (result) Features.push_back(result); else if (Split[I] == "neon" || Split[I] == "noneon") D.Diag(diag::err_drv_no_neon_modifier); else return false; } return true; } // Check if the CPU name and feature modifiers in -mcpu are legal. If yes, // decode CPU and feature. static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, std::vector &Features) { std::pair Split = Mcpu.split("+"); CPU = Split.first; if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57") { Features.push_back("+neon"); Features.push_back("+crc"); Features.push_back("+crypto"); } else if (CPU == "generic") { Features.push_back("+neon"); } else { return false; } if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) return false; return true; } static bool getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, const ArgList &Args, std::vector &Features) { std::pair Split = March.split("+"); if (Split.first != "armv8-a") return false; if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features)) return false; return true; } static bool getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector &Features) { StringRef CPU; if (!DecodeAArch64Mcpu(D, Mcpu, CPU, Features)) return false; return true; } static bool getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector &Features) { // Handle CPU name is 'native'. if (Mtune == "native") Mtune = llvm::sys::getHostCPUName(); if (Mtune == "cyclone") { Features.push_back("+zcm"); Features.push_back("+zcz"); } return true; } static bool getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu, const ArgList &Args, std::vector &Features) { StringRef CPU; std::vector DecodedFeature; if (!DecodeAArch64Mcpu(D, Mcpu, CPU, DecodedFeature)) return false; return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features); } static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, std::vector &Features) { Arg *A; bool success = true; // Enable NEON by default. Features.push_back("+neon"); if ((A = Args.getLastArg(options::OPT_march_EQ))) success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features); else if (Args.hasArg(options::OPT_arch)) success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args), Args, Features); if (success && (A = Args.getLastArg(options::OPT_mtune_EQ))) success = getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features); else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ))) success = getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features); else if (Args.hasArg(options::OPT_arch)) success = getAArch64MicroArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args), Args, Features); if (!success) D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { Features.push_back("-fp-armv8"); Features.push_back("-crypto"); Features.push_back("-neon"); } // En/disable crc if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) { if (A->getOption().matches(options::OPT_mcrc)) Features.push_back("+crc"); else Features.push_back("-crc"); } } static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { std::vector Features; switch (Triple.getArch()) { default: break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: getMIPSTargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: getARMTargetFeatures(D, Triple, Args, Features, ForAS); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: getPPCTargetFeatures(Args, Features); break; case llvm::Triple::sparc: case llvm::Triple::sparcv9: getSparcTargetFeatures(Args, Features); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: getAArch64TargetFeatures(D, Args, Features); break; case llvm::Triple::x86: case llvm::Triple::x86_64: getX86TargetFeatures(D, Triple, Args, Features); break; } // Find the last of each feature. llvm::StringMap LastOpt; for (unsigned I = 0, N = Features.size(); I < N; ++I) { const char *Name = Features[I]; assert(Name[0] == '-' || Name[0] == '+'); LastOpt[Name + 1] = I; } for (unsigned I = 0, N = Features.size(); I < N; ++I) { // If this feature was overridden, ignore it. const char *Name = Features[I]; llvm::StringMap::iterator LastI = LastOpt.find(Name + 1); assert(LastI != LastOpt.end()); unsigned Last = LastI->second; if (Last != I) continue; CmdArgs.push_back("-target-feature"); CmdArgs.push_back(Name); } } static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { // We use the zero-cost exception tables for Objective-C if the non-fragile // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and // later. if (runtime.isNonFragile()) return true; if (!Triple.isMacOSX()) return false; return (!Triple.isMacOSXVersionLT(10,5) && (Triple.getArch() == llvm::Triple::x86_64 || Triple.getArch() == llvm::Triple::arm)); } // exceptionSettings() exists to share the logic between -cc1 and linker // invocations. static bool exceptionSettings(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_fexceptions, options::OPT_fno_exceptions)) if (A->getOption().matches(options::OPT_fexceptions)) return true; return false; } /// addExceptionArgs - Adds exception related arguments to the driver command /// arguments. There's a master flag, -fexceptions and also language specific /// flags to enable/disable C++ and Objective-C exceptions. /// This makes it possible to for example disable C++ exceptions but enable /// Objective-C exceptions. static void addExceptionArgs(const ArgList &Args, types::ID InputType, const llvm::Triple &Triple, bool KernelOrKext, const ObjCRuntime &objcRuntime, ArgStringList &CmdArgs) { if (KernelOrKext) { // -mkernel and -fapple-kext imply no exceptions, so claim exception related // arguments now to avoid warnings about unused arguments. Args.ClaimAllArgs(options::OPT_fexceptions); Args.ClaimAllArgs(options::OPT_fno_exceptions); Args.ClaimAllArgs(options::OPT_fobjc_exceptions); Args.ClaimAllArgs(options::OPT_fno_objc_exceptions); Args.ClaimAllArgs(options::OPT_fcxx_exceptions); Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions); return; } // Gather the exception settings from the command line arguments. bool EH = exceptionSettings(Args, Triple); // Obj-C exceptions are enabled by default, regardless of -fexceptions. This // is not necessarily sensible, but follows GCC. if (types::isObjC(InputType) && Args.hasFlag(options::OPT_fobjc_exceptions, options::OPT_fno_objc_exceptions, true)) { CmdArgs.push_back("-fobjc-exceptions"); EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple); } if (types::isCXX(InputType)) { bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore; if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, options::OPT_fexceptions, options::OPT_fno_exceptions)) CXXExceptionsEnabled = A->getOption().matches(options::OPT_fcxx_exceptions) || A->getOption().matches(options::OPT_fexceptions); if (CXXExceptionsEnabled) { CmdArgs.push_back("-fcxx-exceptions"); EH = true; } } if (EH) CmdArgs.push_back("-fexceptions"); } static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { bool Default = true; if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support the linker_option directives, // so we disable them if we think the .s file will be passed to it. Default = TC.useIntegratedAs(); } return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, Default); } static bool ShouldDisableDwarfDirectory(const ArgList &Args, const ToolChain &TC) { bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm, options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs()); return !UseDwarfDirectory; } /// \brief Check whether the given input tree contains any compilation actions. static bool ContainsCompileAction(const Action *A) { if (isa(A) || isa(A)) return true; for (const auto &Act : *A) if (ContainsCompileAction(Act)) return true; return false; } /// \brief Check if -relax-all should be passed to the internal assembler. /// This is done by default when compiling non-assembler source with -O0. static bool UseRelaxAll(Compilation &C, const ArgList &Args) { bool RelaxDefault = true; if (Arg *A = Args.getLastArg(options::OPT_O_Group)) RelaxDefault = A->getOption().matches(options::OPT_O0); if (RelaxDefault) { RelaxDefault = false; for (const auto &Act : C.getActions()) { if (ContainsCompileAction(Act)) { RelaxDefault = true; break; } } } return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, RelaxDefault); } static void CollectArgsForIntegratedAssembler(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const Driver &D) { if (UseRelaxAll(C, Args)) CmdArgs.push_back("-mrelax-all"); // When passing -I arguments to the assembler we sometimes need to // unconditionally take the next argument. For example, when parsing // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo' // arg after parsing the '-I' arg. bool TakeNextArg = false; // When using an integrated assembler, translate -Wa, and -Xassembler // options. bool CompressDebugSections = false; for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA, options::OPT_Xassembler), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { StringRef Value = A->getValue(i); if (TakeNextArg) { CmdArgs.push_back(Value.data()); TakeNextArg = false; continue; } if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. } else if (Value == "-L") { CmdArgs.push_back("-msave-temp-labels"); } else if (Value == "--fatal-warnings") { CmdArgs.push_back("-massembler-fatal-warnings"); } else if (Value == "--noexecstack") { CmdArgs.push_back("-mnoexecstack"); } else if (Value == "-compress-debug-sections" || Value == "--compress-debug-sections") { CompressDebugSections = true; } else if (Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { CompressDebugSections = false; } else if (Value.startswith("-I")) { CmdArgs.push_back(Value.data()); // We need to consume the next argument if the current arg is a plain // -I. The next arg will be the include directory. if (Value == "-I") TakeNextArg = true; } else if (Value.startswith("-gdwarf-")) { CmdArgs.push_back(Value.data()); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } } } if (CompressDebugSections) { if (llvm::zlib::isAvailable()) CmdArgs.push_back("-compress-debug-sections"); else D.Diag(diag::warn_debug_compression_unavailable); } } // Until ARM libraries are build separately, we have them all in one library static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) { // FIXME: handle 64-bit if (TC.getTriple().isOSWindows() && !TC.getTriple().isWindowsItaniumEnvironment()) return "i386"; if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) return "arm"; return TC.getArchName(); } static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) { // The runtimes are located in the OS-specific resource directory. SmallString<128> Res(TC.getDriver().ResourceDir); const llvm::Triple &Triple = TC.getTriple(); // TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected. StringRef OSLibName = (Triple.getOS() == llvm::Triple::FreeBSD) ? "freebsd" : TC.getOS(); llvm::sys::path::append(Res, "lib", OSLibName); return Res; } static SmallString<128> getCompilerRT(const ToolChain &TC, StringRef Component, bool Shared = false, const char *Env = "") { bool IsOSWindows = TC.getTriple().isOSWindows(); StringRef Arch = getArchNameForCompilerRTLib(TC); const char *Prefix = IsOSWindows ? "" : "lib"; const char *Suffix = Shared ? (IsOSWindows ? ".dll" : ".so") : (IsOSWindows ? ".lib" : ".a"); SmallString<128> Path = getCompilerRTLibDir(TC); llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + Arch + Env + Suffix); return Path; } // This adds the static libclang_rt.builtins-arch.a directly to the command line // FIXME: Make sure we can also emit shared objects if they're requested // and available, check for possible errors, etc. static void addClangRT(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "builtins"))); if (!TC.getTriple().isOSWindows()) { // FIXME: why do we link against gcc when we are using compiler-rt? CmdArgs.push_back("-lgcc_s"); if (TC.getDriver().CCCIsCXX()) CmdArgs.push_back("-lgcc_eh"); } } static void addProfileRT(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_fprofile_generate) || Args.hasArg(options::OPT_fprofile_instr_generate) || Args.hasArg(options::OPT_fcreate_profile) || Args.hasArg(options::OPT_coverage))) return; CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "profile"))); } static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, bool IsShared) { const char *Env = TC.getTriple().getEnvironment() == llvm::Triple::Android ? "-android" : ""; // Static runtimes must be forced into executable, so we wrap them in // whole-archive. if (!IsShared) CmdArgs.push_back("-whole-archive"); CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Sanitizer, IsShared, Env))); if (!IsShared) CmdArgs.push_back("-no-whole-archive"); } // Tries to use a file with the list of dynamic symbols that need to be exported // from the runtime library. Returns true if the file was found. static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer) { SmallString<128> SanRT = getCompilerRT(TC, Sanitizer); if (llvm::sys::fs::exists(SanRT + ".syms")) { CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); return true; } return false; } static void linkSanitizerRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). CmdArgs.push_back("--no-as-needed"); CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lrt"); CmdArgs.push_back("-lm"); // There's no libdl on FreeBSD. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) CmdArgs.push_back("-ldl"); } static void collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl &SharedRuntimes, SmallVectorImpl &StaticRuntimes, SmallVectorImpl &HelperStaticRuntimes) { const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Collect shared runtimes. if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { SharedRuntimes.push_back("asan"); } // Collect static runtimes. if (Args.hasArg(options::OPT_shared) || (TC.getTriple().getEnvironment() == llvm::Triple::Android)) { // Don't link static runtimes into DSOs or if compiling for Android. return; } if (SanArgs.needsAsanRt()) { if (SanArgs.needsSharedAsanRt()) { HelperStaticRuntimes.push_back("asan-preinit"); } else { StaticRuntimes.push_back("asan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("asan_cxx"); } } if (SanArgs.needsDfsanRt()) StaticRuntimes.push_back("dfsan"); if (SanArgs.needsLsanRt()) StaticRuntimes.push_back("lsan"); if (SanArgs.needsMsanRt()) StaticRuntimes.push_back("msan"); if (SanArgs.needsTsanRt()) StaticRuntimes.push_back("tsan"); // WARNING: UBSan should always go last. if (SanArgs.needsUbsanRt()) { // If UBSan is not combined with another sanitizer, we need to pull in // sanitizer_common explicitly. if (StaticRuntimes.empty()) HelperStaticRuntimes.push_back("san"); StaticRuntimes.push_back("ubsan"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("ubsan_cxx"); } } // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { SmallVector SharedRuntimes, StaticRuntimes, HelperStaticRuntimes; collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, HelperStaticRuntimes); for (auto RT : SharedRuntimes) addSanitizerRuntime(TC, Args, CmdArgs, RT, true); for (auto RT : HelperStaticRuntimes) addSanitizerRuntime(TC, Args, CmdArgs, RT, false); bool AddExportDynamic = false; for (auto RT : StaticRuntimes) { addSanitizerRuntime(TC, Args, CmdArgs, RT, false); AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); } // If there is a static runtime with no dynamic list, force all the symbols // to be dynamic to be sure we export sanitizer interface functions. if (AddExportDynamic) CmdArgs.push_back("-export-dynamic"); return !StaticRuntimes.empty(); } static bool shouldUseFramePointerForTarget(const ArgList &Args, const llvm::Triple &Triple) { switch (Triple.getArch()) { // Don't use a frame pointer on linux if optimizing for certain targets. case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::systemz: case llvm::Triple::x86: case llvm::Triple::x86_64: if (Triple.isOSLinux()) if (Arg *A = Args.getLastArg(options::OPT_O_Group)) if (!A->getOption().matches(options::OPT_O0)) return false; return true; case llvm::Triple::xcore: return false; default: return true; } } static bool shouldUseFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) return A->getOption().matches(options::OPT_fno_omit_frame_pointer); return shouldUseFramePointerForTarget(Args, Triple); } static bool shouldUseLeafFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, options::OPT_momit_leaf_frame_pointer)) return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); return shouldUseFramePointerForTarget(Args, Triple); } /// Add a CC1 option to specify the debug compilation directory. static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { SmallString<128> cwd; if (!llvm::sys::fs::current_path(cwd)) { CmdArgs.push_back("-fdebug-compilation-dir"); CmdArgs.push_back(Args.MakeArgString(cwd)); } } static const char *SplitDebugName(const ArgList &Args, const InputInfoList &Inputs) { Arg *FinalOutput = Args.getLastArg(options::OPT_o); if (FinalOutput && Args.hasArg(options::OPT_c)) { SmallString<128> T(FinalOutput->getValue()); llvm::sys::path::replace_extension(T, "dwo"); return Args.MakeArgString(T); } else { // Use the compilation dir. SmallString<128> T( Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); SmallString<128> F(llvm::sys::path::stem(Inputs[0].getBaseInput())); llvm::sys::path::replace_extension(F, "dwo"); T += F; return Args.MakeArgString(F); } } static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, const JobAction &JA, const ArgList &Args, const InputInfo &Output, const char *OutFile) { ArgStringList ExtractArgs; ExtractArgs.push_back("--extract-dwo"); ArgStringList StripArgs; StripArgs.push_back("--strip-dwo"); // Grabbing the output of the earlier compile step. StripArgs.push_back(Output.getFilename()); ExtractArgs.push_back(Output.getFilename()); ExtractArgs.push_back(OutFile); const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); // First extract the dwo sections. C.addCommand(llvm::make_unique(JA, T, Exec, ExtractArgs)); // Then remove them from the original .o file. C.addCommand(llvm::make_unique(JA, T, Exec, StripArgs)); } /// \brief Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O4) || A->getOption().matches(options::OPT_Ofast)) return true; if (A->getOption().matches(options::OPT_O0)) return false; assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); // Vectorize -Os. StringRef S(A->getValue()); if (S == "s") return true; // Don't vectorize -Oz, unless it's the slp vectorizer. if (S == "z") return isSlpVec; unsigned OptLevel = 0; if (S.getAsInteger(10, OptLevel)) return false; return OptLevel > 1; } return false; } /// Add -x lang to \p CmdArgs for \p Input. static void addDashXForInput(const ArgList &Args, const InputInfo &Input, ArgStringList &CmdArgs) { // When using -verify-pch, we don't want to provide the type // 'precompiled-header' if it was inferred from the file extension if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH) return; CmdArgs.push_back("-x"); if (Args.hasArg(options::OPT_rewrite_objc)) CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); else CmdArgs.push_back(types::getTypeName(Input.getType())); } static std::string getMSCompatibilityVersion(const char *VersionStr) { unsigned Version; if (StringRef(VersionStr).getAsInteger(10, Version)) return "0"; if (Version < 100) return llvm::utostr_32(Version) + ".0"; if (Version < 10000) return llvm::utostr_32(Version / 100) + "." + llvm::utostr_32(Version % 100); unsigned Build = 0, Factor = 1; for ( ; Version > 10000; Version = Version / 10, Factor = Factor * 10) Build = Build + (Version % 10) * Factor; return llvm::utostr_32(Version / 100) + "." + llvm::utostr_32(Version % 100) + "." + llvm::utostr_32(Build); } // Claim options we don't want to warn if they are unused. We do this for // options that build systems might add but are unused when assembling or only // running the preprocessor for example. static void claimNoWarnArgs(const ArgList &Args) { // Don't warn about unused -f(no-)?lto. This can happen when we're // preprocessing, precompiling or assembling. Args.ClaimAllArgs(options::OPT_flto); Args.ClaimAllArgs(options::OPT_fno_lto); } void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment(); bool IsWindowsCygnus = getToolChain().getTriple().isWindowsCygwinEnvironment(); bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); // Invoke ourselves in -cc1 mode. // // FIXME: Implement custom jobs for internal actions. CmdArgs.push_back("-cc1"); // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); CmdArgs.push_back(Args.MakeArgString(TripleStr)); const llvm::Triple TT(TripleStr); if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm || TT.getArch() == llvm::Triple::thumb)) { unsigned Offset = TT.getArch() == llvm::Triple::arm ? 4 : 6; unsigned Version; TT.getArchName().substr(Offset).getAsInteger(10, Version); if (Version < 7) D.Diag(diag::err_target_unsupported_arch) << TT.getArchName() << TripleStr; } // Push all default warning arguments that are specific to // the given target. These come before user provided warning options // are provided. getToolChain().addClangWarningOptions(CmdArgs); // Select the appropriate action. RewriteKind rewriteKind = RK_None; if (isa(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); } else if (isa(JA)) { CmdArgs.push_back("-migrate"); } else if (isa(JA)) { if (Output.getType() == types::TY_Dependencies) CmdArgs.push_back("-Eonly"); else { CmdArgs.push_back("-E"); if (Args.hasArg(options::OPT_rewrite_objc) && !Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("-P"); } } else if (isa(JA)) { CmdArgs.push_back("-emit-obj"); CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); // Also ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); } else if (isa(JA)) { // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; if (JA.getType() == types::TY_Nothing) CmdArgs.push_back("-fsyntax-only"); else if (UsePCH) CmdArgs.push_back("-emit-pch"); else CmdArgs.push_back("-emit-pth"); } else if (isa(JA)) { CmdArgs.push_back("-verify-pch"); } else { assert((isa(JA) || isa(JA)) && "Invalid action for clang tool."); if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); } else if (JA.getType() == types::TY_LLVM_IR || JA.getType() == types::TY_LTO_IR) { CmdArgs.push_back("-emit-llvm"); } else if (JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) { CmdArgs.push_back("-emit-llvm-bc"); } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { CmdArgs.push_back("-emit-pch"); } else if (JA.getType() == types::TY_ModuleFile) { CmdArgs.push_back("-module-file-info"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_NonFragile; } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { CmdArgs.push_back("-rewrite-objc"); rewriteKind = RK_Fragile; } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); } } // We normally speed up the clang process a bit by skipping destructors at // exit, but when we're generating diagnostics we can rely on some of the // cleanup. if (!C.isForDiagnostics()) CmdArgs.push_back("-disable-free"); // Disable the verification pass in -asserts builds. #ifdef NDEBUG CmdArgs.push_back("-disable-llvm-verifier"); #endif // Set the main file name, so that debug info works even with // -save-temps. CmdArgs.push_back("-main-file-name"); CmdArgs.push_back(getBaseInputName(Args, Inputs)); // Some flags which affect the language (via preprocessor // defines). if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-static-define"); if (isa(JA)) { // Enable region store model by default. CmdArgs.push_back("-analyzer-store=region"); // Treat blocks as analysis entry points. CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); CmdArgs.push_back("-analyzer-eagerly-assume"); // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); if (!IsWindowsMSVC) CmdArgs.push_back("-analyzer-checker=unix"); if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) CmdArgs.push_back("-analyzer-checker=osx"); CmdArgs.push_back("-analyzer-checker=deadcode"); if (types::isCXX(Inputs[0].getType())) CmdArgs.push_back("-analyzer-checker=cplusplus"); // Enable the following experimental checkers for testing. CmdArgs.push_back( "-analyzer-checker=security.insecureAPI.UncheckedReturn"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); } // Set the output format. The default is plist, for (lame) historical // reasons. CmdArgs.push_back("-analyzer-output"); if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) CmdArgs.push_back(A->getValue()); else CmdArgs.push_back("plist"); // Disable the presentation of standard compiler warnings when // using --analyze. We only want to show static analyzer diagnostics // or frontend errors. CmdArgs.push_back("-w"); // Add -Xanalyzer arguments when running as analyzer. Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); } CheckCodeGenerationOptions(D, Args); bool PIE = getToolChain().isPIEDefault(); bool PIC = PIE || getToolChain().isPICDefault(); bool IsPICLevelTwo = PIC; // Android-specific defaults for PIC/PIE if (getToolChain().getTriple().getEnvironment() == llvm::Triple::Android) { switch (getToolChain().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::aarch64: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: PIC = true; // "-fpic" break; case llvm::Triple::x86: case llvm::Triple::x86_64: PIC = true; // "-fPIC" IsPICLevelTwo = true; break; default: break; } } // OpenBSD-specific defaults for PIE if (getToolChain().getTriple().getOS() == llvm::Triple::OpenBSD) { switch (getToolChain().getTriple().getArch()) { case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::sparc: case llvm::Triple::x86: case llvm::Triple::x86_64: IsPICLevelTwo = false; // "-fpie" break; case llvm::Triple::ppc: case llvm::Triple::sparcv9: IsPICLevelTwo = true; // "-fPIE" break; default: break; } } // For the PIC and PIE flag options, this logic is different from the // legacy logic in very old versions of GCC, as that logic was just // a bug no one had ever fixed. This logic is both more rational and // consistent with GCC's new logic now that the bugs are fixed. The last // argument relating to either PIC or PIE wins, and no other argument is // used. If the last argument is any flavor of the '-fno-...' arguments, // both PIC and PIE are disabled. Any PIE option implicitly enables PIC // at the same level. Arg *LastPICArg =Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie); // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. if (!getToolChain().isPICDefaultForced()) { if (LastPICArg) { Option O = LastPICArg->getOption(); if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); IsPICLevelTwo = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); } else { PIE = PIC = false; } } } // Introduce a Darwin-specific hack. If the default is PIC but the flags // specified while enabling PIC enabled level 1 PIC, just force it back to // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my // informal testing). if (PIC && getToolChain().getTriple().isOSDarwin()) IsPICLevelTwo |= getToolChain().isPICDefault(); // Note that these flags are trump-cards. Regardless of the order w.r.t. the // PIC or PIE options above, if these show up, PIC is disabled. llvm::Triple Triple(TripleStr); if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6))) PIC = PIE = false; if (Args.hasArg(options::OPT_static)) PIC = PIE = false; if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { // This is a very special mode. It trumps the other modes, almost no one // uses it, and it isn't even valid on any OS but Darwin. if (!getToolChain().getTriple().isOSDarwin()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getSpelling() << getToolChain().getTriple().str(); // FIXME: Warn when this flag trumps some other PIC or PIE flag. CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back("dynamic-no-pic"); // Only a forced PIC mode can cause the actual compile to have PIC defines // etc., no flags are sufficient. This behavior was selected to closely // match that of llvm-gcc and Apple GCC before that. if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) { CmdArgs.push_back("-pic-level"); CmdArgs.push_back("2"); } } else { // Currently, LLVM only knows about PIC vs. static; the PIE differences are // handled in Clang's IRGen by the -pie-level flag. CmdArgs.push_back("-mrelocation-model"); CmdArgs.push_back(PIC ? "pic" : "static"); if (PIC) { CmdArgs.push_back("-pic-level"); CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); if (PIE) { CmdArgs.push_back("-pie-level"); CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); } } } CmdArgs.push_back("-mthread-model"); if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) CmdArgs.push_back(A->getValue()); else CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel())); if (!Args.hasFlag(options::OPT_fmerge_all_constants, options::OPT_fno_merge_all_constants)) CmdArgs.push_back("-fno-merge-all-constants"); // LLVM Code Generator Options. if (Args.hasArg(options::OPT_frewrite_map_file) || Args.hasArg(options::OPT_frewrite_map_file_EQ)) { for (arg_iterator MFI = Args.filtered_begin(options::OPT_frewrite_map_file, options::OPT_frewrite_map_file_EQ), MFE = Args.filtered_end(); MFI != MFE; ++MFI) { CmdArgs.push_back("-frewrite-map-file"); CmdArgs.push_back((*MFI)->getValue()); (*MFI)->claim(); } } if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { StringRef v = A->getValue(); CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v)); A->claim(); } if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, options::OPT_freg_struct_return)) { if (getToolChain().getArch() != llvm::Triple::x86) { D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getSpelling() << getToolChain().getTriple().str(); } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { CmdArgs.push_back("-fpcc-struct-return"); } else { assert(A->getOption().matches(options::OPT_freg_struct_return)); CmdArgs.push_back("-freg-struct-return"); } } if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-mrtd"); if (shouldUseFramePointer(Args, getToolChain().getTriple())) CmdArgs.push_back("-mdisable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); bool OFastEnabled = isOptimizationLevelFast(Args); // If -Ofast is the optimization level, then -fstrict-aliasing should be // enabled. This alias option is being used to simplify the hasFlag logic. OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; // We turn strict aliasing off by default if we're in CL mode, since MSVC // doesn't do any TBAA. bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode(); if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, options::OPT_fno_strict_aliasing, TBAAOnByDefault)) CmdArgs.push_back("-relaxed-aliasing"); if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, options::OPT_fno_struct_path_tbaa)) CmdArgs.push_back("-no-struct-path-tbaa"); if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); // Handle segmented stacks. if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("-split-stacks"); // If -Ofast is the optimization level, then -ffast-math should be enabled. // This alias option is being used to simplify the getLastArg logic. OptSpecifier FastMathAliasOption = OFastEnabled ? options::OPT_Ofast : options::OPT_ffast_math; // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. The pattern for all of these is to // default off the codegen optimizations, and if any flag enables them and no // flag disables them after the flag enabling them, enable the codegen // optimization. This is complicated by several "umbrella" flags. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, options::OPT_fhonor_infinities, options::OPT_fno_honor_infinities)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_infinities) CmdArgs.push_back("-menable-no-infs"); if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, options::OPT_fhonor_nans, options::OPT_fno_honor_nans)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_nans) CmdArgs.push_back("-menable-no-nans"); // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = getToolChain().IsMathErrnoDefault(); if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_fmath_errno, options::OPT_fno_math_errno)) { // Turning on -ffast_math (with either flag) removes the need for MathErrno. // However, turning *off* -ffast_math merely restores the toolchain default // (which may be false). if (A->getOption().getID() == options::OPT_fno_math_errno || A->getOption().getID() == options::OPT_ffast_math || A->getOption().getID() == options::OPT_Ofast) MathErrno = false; else if (A->getOption().getID() == options::OPT_fmath_errno) MathErrno = true; } if (MathErrno) CmdArgs.push_back("-fmath-errno"); // There are several flags which require disabling very specific // optimizations. Any of these being disabled forces us to turn off the // entire set of LLVM optimizations, so collect them through all the flag // madness. bool AssociativeMath = false; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_fassociative_math, options::OPT_fno_associative_math)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fno_associative_math) AssociativeMath = true; bool ReciprocalMath = false; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fno_reciprocal_math) ReciprocalMath = true; bool SignedZeros = true; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fsigned_zeros) SignedZeros = false; bool TrappingMath = true; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_ftrapping_math, options::OPT_fno_trapping_math)) if (A->getOption().getID() != options::OPT_fno_fast_math && A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_ftrapping_math) TrappingMath = false; if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && !TrappingMath) CmdArgs.push_back("-menable-unsafe-fp-math"); // Validate and pass through -fp-contract option. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffp_contract)) { if (A->getOption().getID() == options::OPT_ffp_contract) { StringRef Val = A->getValue(); if (Val == "fast" || Val == "on" || Val == "off") { CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val)); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } } else if (A->getOption().matches(options::OPT_ffast_math) || (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) { // If fast-math is set then set the fp-contract mode to fast. CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); } } // We separately look for the '-ffast-math' and '-ffinite-math-only' flags, // and if we find them, tell the frontend to provide the appropriate // preprocessor macros. This is distinct from enabling any optimizations as // these options induce language changes which must survive serialization // and deserialization, etc. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math)) if (!A->getOption().matches(options::OPT_fno_fast_math)) CmdArgs.push_back("-ffast-math"); if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math)) if (A->getOption().matches(options::OPT_ffinite_math_only)) CmdArgs.push_back("-ffinite-math-only"); // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsIntegratedAssemblerDefault = getToolChain().IsIntegratedAssemblerDefault(); if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, IsIntegratedAssemblerDefault) || Args.hasArg(options::OPT_dA)) CmdArgs.push_back("-masm-verbose"); if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as, IsIntegratedAssemblerDefault)) CmdArgs.push_back("-no-integrated-as"); if (Args.hasArg(options::OPT_fdebug_pass_structure)) { CmdArgs.push_back("-mdebug-pass"); CmdArgs.push_back("Structure"); } if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { CmdArgs.push_back("-mdebug-pass"); CmdArgs.push_back("Arguments"); } // Enable -mconstructor-aliases except on darwin, where we have to // work around a linker bug; see . if (!getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we // try to use them. if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasArg(options::OPT_mms_bitfields)) { CmdArgs.push_back("-mms-bitfields"); } // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. bool AsynchronousUnwindTables = Args.hasFlag(options::OPT_fasynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables, (getToolChain().IsUnwindTablesDefault() || getToolChain().getSanitizerArgs().needsUnwindTables()) && !KernelOrKext); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); getToolChain().addClangTargetOptions(Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); CmdArgs.push_back(A->getValue()); } // FIXME: Handle -mtune=. (void) Args.hasArg(options::OPT_mtune_EQ); if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { CmdArgs.push_back("-mcode-model"); CmdArgs.push_back(A->getValue()); } // Add the target cpu std::string ETripleStr = getToolChain().ComputeEffectiveClangTriple(Args); llvm::Triple ETriple(ETripleStr); std::string CPU = getCPUName(Args, ETriple); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); } if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { CmdArgs.push_back("-mfpmath"); CmdArgs.push_back(A->getValue()); } // Add the target features getTargetFeatures(D, ETriple, Args, CmdArgs, false); // Add target specific flags. switch(getToolChain().getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: AddARMTargetArgs(Args, CmdArgs, KernelOrKext); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: AddAArch64TargetArgs(Args, CmdArgs); break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: AddMIPSTargetArgs(Args, CmdArgs); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: AddPPCTargetArgs(Args, CmdArgs); break; case llvm::Triple::sparc: case llvm::Triple::sparcv9: AddSparcTargetArgs(Args, CmdArgs); break; case llvm::Triple::x86: case llvm::Triple::x86_64: AddX86TargetArgs(Args, CmdArgs); break; case llvm::Triple::hexagon: AddHexagonTargetArgs(Args, CmdArgs); break; } // Add clang-cl arguments. if (getToolChain().getDriver().IsCLMode()) AddClangCLArgs(Args, CmdArgs); // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { CmdArgs.push_back("-target-linker-version"); CmdArgs.push_back(A->getValue()); } if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple())) CmdArgs.push_back("-momit-leaf-frame-pointer"); // Explicitly error on some things we know we don't support and can't just // ignore. types::ID InputType = Inputs[0].getType(); if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && getToolChain().getArch() == llvm::Triple::x86) { if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || (Unsupported = Args.getLastArg(options::OPT_mkernel))) D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) << Unsupported->getOption().getName(); } } Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_H); if (D.CCPrintHeaders && !D.CCGenDiagnostics) { CmdArgs.push_back("-header-include-file"); CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename : "-"); } Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { CmdArgs.push_back("-diagnostic-log-file"); CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename : "-"); } // Use the last option from "-g" group. "-gline-tables-only" and "-gdwarf-x" // are preserved, all other debug options are substituted with "-g". Args.ClaimAllArgs(options::OPT_g_Group); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { if (A->getOption().matches(options::OPT_gline_tables_only) || A->getOption().matches(options::OPT_g1)) { // FIXME: we should support specifying dwarf version with // -gline-tables-only. CmdArgs.push_back("-gline-tables-only"); // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. const llvm::Triple &Triple = getToolChain().getTriple(); if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || Triple.getOS() == llvm::Triple::FreeBSD || Triple.getOS() == llvm::Triple::Solaris) CmdArgs.push_back("-gdwarf-2"); } else if (A->getOption().matches(options::OPT_gdwarf_2)) CmdArgs.push_back("-gdwarf-2"); else if (A->getOption().matches(options::OPT_gdwarf_3)) CmdArgs.push_back("-gdwarf-3"); else if (A->getOption().matches(options::OPT_gdwarf_4)) CmdArgs.push_back("-gdwarf-4"); else if (!A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_ggdb0)) { // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. const llvm::Triple &Triple = getToolChain().getTriple(); if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || Triple.getOS() == llvm::Triple::FreeBSD || Triple.getOS() == llvm::Triple::Solaris) CmdArgs.push_back("-gdwarf-2"); else CmdArgs.push_back("-g"); } } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, /*Default*/ true)) CmdArgs.push_back("-dwarf-column-info"); // FIXME: Move backend command line options to the module. // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. if (getToolChain().getTriple().isOSLinux() && Args.hasArg(options::OPT_gsplit_dwarf)) { CmdArgs.push_back("-g"); CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } // -ggnu-pubnames turns on gnu style pubnames in the backend. if (Args.hasArg(options::OPT_ggnu_pubnames)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-generate-gnu-dwarf-pub-sections"); } // -gdwarf-aranges turns on the emission of the aranges section in the // backend. if (Args.hasArg(options::OPT_gdwarf_aranges)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-generate-arange-section"); } if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-generate-type-units"); } if (Args.hasFlag(options::OPT_ffunction_sections, options::OPT_fno_function_sections, false)) { CmdArgs.push_back("-ffunction-sections"); } if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, false)) { CmdArgs.push_back("-fdata-sections"); } Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); if (Args.hasArg(options::OPT_fprofile_instr_generate) && (Args.hasArg(options::OPT_fprofile_instr_use) || Args.hasArg(options::OPT_fprofile_instr_use_EQ))) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fprofile-instr-generate" << "-fprofile-instr-use"; Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate); if (Arg *A = Args.getLastArg(options::OPT_fprofile_instr_use_EQ)) A->render(Args, CmdArgs); else if (Args.hasArg(options::OPT_fprofile_instr_use)) CmdArgs.push_back("-fprofile-instr-use=pgo-data"); if (Args.hasArg(options::OPT_ftest_coverage) || Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-notes"); if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, false) || Args.hasArg(options::OPT_coverage)) CmdArgs.push_back("-femit-coverage-data"); if (Args.hasArg(options::OPT_fcoverage_mapping) && !Args.hasArg(options::OPT_fprofile_instr_generate)) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fcoverage-mapping" << "-fprofile-instr-generate"; if (Args.hasArg(options::OPT_fcoverage_mapping)) CmdArgs.push_back("-fcoverage-mapping"); if (C.getArgs().hasArg(options::OPT_c) || C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { CmdArgs.push_back("-coverage-file"); SmallString<128> CoverageFilename; if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) { CoverageFilename = FinalOutput->getValue(); } else { CoverageFilename = llvm::sys::path::filename(Output.getBaseInput()); } if (llvm::sys::path::is_relative(CoverageFilename.str())) { SmallString<128> Pwd; if (!llvm::sys::fs::current_path(Pwd)) { llvm::sys::path::append(Pwd, CoverageFilename.str()); CoverageFilename.swap(Pwd); } } CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); } } // Pass options for controlling the default header search paths. if (Args.hasArg(options::OPT_nostdinc)) { CmdArgs.push_back("-nostdsysteminc"); CmdArgs.push_back("-nobuiltininc"); } else { if (Args.hasArg(options::OPT_nostdlibinc)) CmdArgs.push_back("-nostdsysteminc"); Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); } // Pass the path to compiler resource files. CmdArgs.push_back("-resource-dir"); CmdArgs.push_back(D.ResourceDir.c_str()); Args.AddLastArg(CmdArgs, options::OPT_working_directory); bool ARCMTEnabled = false; if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_modify, options::OPT_ccc_arcmt_migrate)) { ARCMTEnabled = true; switch (A->getOption().getID()) { default: llvm_unreachable("missed a case"); case options::OPT_ccc_arcmt_check: CmdArgs.push_back("-arcmt-check"); break; case options::OPT_ccc_arcmt_modify: CmdArgs.push_back("-arcmt-modify"); break; case options::OPT_ccc_arcmt_migrate: CmdArgs.push_back("-arcmt-migrate"); CmdArgs.push_back("-mt-migrate-directory"); CmdArgs.push_back(A->getValue()); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); break; } } } else { Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); } if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { if (ARCMTEnabled) { D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-ccc-arcmt-migrate"; } CmdArgs.push_back("-mt-migrate-directory"); CmdArgs.push_back(A->getValue()); if (!Args.hasArg(options::OPT_objcmt_migrate_literals, options::OPT_objcmt_migrate_subscripting, options::OPT_objcmt_migrate_property)) { // None specified, means enable them all. CmdArgs.push_back("-objcmt-migrate-literals"); CmdArgs.push_back("-objcmt-migrate-subscripting"); CmdArgs.push_back("-objcmt-migrate-property"); } else { Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); } } else { Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); } // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. // // FIXME: Support -fpreprocessed if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs); // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes // that "The compiler can only warn and ignore the option if not recognized". // When building with ccache, it will pass -D options to clang even on // preprocessed inputs and configure concludes that -fPIC is not supported. Args.ClaimAllArgs(options::OPT_D); // Manually translate -O4 to -O3; let clang reject others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O4)) { CmdArgs.push_back("-O3"); D.Diag(diag::warn_O4_is_O3); } else { A->render(Args, CmdArgs); } } // Warn about ignored options to clang. for (arg_iterator it = Args.filtered_begin( options::OPT_clang_ignored_gcc_optimization_f_Group), ie = Args.filtered_end(); it != ie; ++it) { D.Diag(diag::warn_ignored_gcc_optimization) << (*it)->getAsString(Args); } claimNoWarnArgs(Args); Args.AddAllArgs(CmdArgs, options::OPT_R_Group); Args.AddAllArgs(CmdArgs, options::OPT_W_Group); if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // // If a std is supplied, only add -trigraphs if it follows the // option. if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) if (types::isCXX(InputType)) CmdArgs.push_back("-std=c++98"); else CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); // If -f(no-)trigraphs appears after the language standard flag, honor it. if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi, options::OPT_ftrigraphs, options::OPT_fno_trigraphs)) if (A != Std) A->render(Args, CmdArgs); } else { // Honor -std-default. // // FIXME: Clang doesn't correctly handle -std= when the input language // doesn't match. For the time being just ignore this for C++ inputs; // eventually we want to do all the standard defaulting here instead of // splitting it between the driver and clang -cc1. if (!types::isCXX(InputType)) Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", /*Joined=*/true); else if (IsWindowsMSVC) CmdArgs.push_back("-std=c++11"); Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, options::OPT_fno_trigraphs); } // GCC's behavior for -Wwrite-strings is a bit strange: // * In C, this "warning flag" changes the types of string literals from // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning // for the discarded qualifier. // * In C++, this is just a normal warning flag. // // Implementing this warning correctly in C is hard, so we follow GCC's // behavior for now. FIXME: Directly diagnose uses of a string literal as // a non-const char* in C, rather than using this crude hack. if (!types::isCXX(InputType)) { // FIXME: This should behave just like a warning flag, and thus should also // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on. Arg *WriteStrings = Args.getLastArg(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings, options::OPT_w); if (WriteStrings && WriteStrings->getOption().matches(options::OPT_Wwrite_strings)) CmdArgs.push_back("-fconst-strings"); } // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active // during C++ compilation, which it is by default. GCC keeps this define even // in the presence of '-w', match this behavior bug-for-bug. if (types::isCXX(InputType) && Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, true)) { CmdArgs.push_back("-fdeprecated-macro"); } // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { if (Asm->getOption().matches(options::OPT_fasm)) CmdArgs.push_back("-fgnu-keywords"); else CmdArgs.push_back("-fno-gnu-keywords"); } if (ShouldDisableDwarfDirectory(Args, getToolChain())) CmdArgs.push_back("-fno-dwarf-directory-asm"); if (ShouldDisableAutolink(Args, getToolChain())) CmdArgs.push_back("-fno-autolink"); // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { CmdArgs.push_back("-ftemplate-depth"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { CmdArgs.push_back("-foperator-arrow-depth"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { CmdArgs.push_back("-fconstexpr-depth"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { CmdArgs.push_back("-fconstexpr-steps"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { CmdArgs.push_back("-fbracket-depth"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, options::OPT_Wlarge_by_value_copy_def)) { if (A->getNumValues()) { StringRef bytes = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes)); } else CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value } if (Args.hasArg(options::OPT_relocatable_pch)) CmdArgs.push_back("-relocatable-pch"); if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { CmdArgs.push_back("-fconstant-string-class"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { CmdArgs.push_back("-ftabstop"); CmdArgs.push_back(A->getValue()); } CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) CmdArgs.push_back(A->getValue()); else CmdArgs.push_back("19"); if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { CmdArgs.push_back("-fmacro-backtrace-limit"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { CmdArgs.push_back("-ftemplate-backtrace-limit"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { CmdArgs.push_back("-fconstexpr-backtrace-limit"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { CmdArgs.push_back("-fspell-checking-limit"); CmdArgs.push_back(A->getValue()); } // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { CmdArgs.push_back(A->getValue()); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. unsigned N = llvm::sys::Process::StandardErrColumns(); CmdArgs.push_back(Args.MakeArgString(Twine(N))); } // -fvisibility= and -fvisibility-ms-compat are of a piece. if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, options::OPT_fvisibility_ms_compat)) { if (A->getOption().matches(options::OPT_fvisibility_EQ)) { CmdArgs.push_back("-fvisibility"); CmdArgs.push_back(A->getValue()); } else { assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); CmdArgs.push_back("-fvisibility"); CmdArgs.push_back("hidden"); CmdArgs.push_back("-ftype-visibility"); CmdArgs.push_back("default"); } } Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); // -fhosted is default. if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || KernelOrKext) CmdArgs.push_back("-ffreestanding"); // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug); Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); // AltiVec language extensions aren't relevant for assembling. if (!isa(JA) || Output.getType() != types::TY_PP_Asm) Args.AddLastArg(CmdArgs, options::OPT_faltivec); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); Sanitize.addArgs(Args, CmdArgs); // Report an error for -faltivec on anything other than PowerPC. if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) if (!(getToolChain().getArch() == llvm::Triple::ppc || getToolChain().getArch() == llvm::Triple::ppc64 || getToolChain().getArch() == llvm::Triple::ppc64le)) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "ppc/ppc64/ppc64le"; if (getToolChain().SupportsProfiling()) Args.AddLastArg(CmdArgs, options::OPT_pg); // -flax-vector-conversions is default. if (!Args.hasFlag(options::OPT_flax_vector_conversions, options::OPT_fno_lax_vector_conversions)) CmdArgs.push_back("-fno-lax-vector-conversions"); if (Args.getLastArg(options::OPT_fapple_kext)) CmdArgs.push_back("-fapple-kext"); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue()); } Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); // -fno-strict-overflow implies -fwrapv if it isn't disabled, but // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { if (A->getOption().matches(options::OPT_fwrapv)) CmdArgs.push_back("-fwrapv"); } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, options::OPT_fno_strict_overflow)) { if (A->getOption().matches(options::OPT_fno_strict_overflow)) CmdArgs.push_back("-fwrapv"); } if (Arg *A = Args.getLastArg(options::OPT_freroll_loops, options::OPT_fno_reroll_loops)) if (A->getOption().matches(options::OPT_freroll_loops)) CmdArgs.push_back("-freroll-loops"); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, options::OPT_fno_unroll_loops); Args.AddLastArg(CmdArgs, options::OPT_pthread); // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector_strong, options::OPT_fstack_protector)) { if (A->getOption().matches(options::OPT_fstack_protector)) { StackProtectorLevel = std::max(LangOptions::SSPOn, getToolChain().GetDefaultStackProtectorLevel(KernelOrKext)); } else if (A->getOption().matches(options::OPT_fstack_protector_strong)) StackProtectorLevel = LangOptions::SSPStrong; else if (A->getOption().matches(options::OPT_fstack_protector_all)) StackProtectorLevel = LangOptions::SSPReq; } else { StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); } if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector"); CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); } // --param ssp-buffer-size= for (arg_iterator it = Args.filtered_begin(options::OPT__param), ie = Args.filtered_end(); it != ie; ++it) { StringRef Str((*it)->getValue()); if (Str.startswith("ssp-buffer-size=")) { if (StackProtectorLevel) { CmdArgs.push_back("-stack-protector-buffer-size"); // FIXME: Verify the argument is a valid integer. CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); } (*it)->claim(); } } // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, false)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-force-align-stack"); } if (!Args.hasFlag(options::OPT_mno_stackrealign, options::OPT_mstackrealign, false)) { CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); } if (Args.hasArg(options::OPT_mstack_alignment)) { StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); } if (getToolChain().getTriple().getArch() == llvm::Triple::aarch64 || getToolChain().getTriple().getArch() == llvm::Triple::aarch64_be) CmdArgs.push_back("-fallow-half-arguments-and-returns"); if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-restrict-it"); } else { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-no-restrict-it"); } } else if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm || TT.getArch() == llvm::Triple::thumb)) { // Windows on ARM expects restricted IT blocks CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-restrict-it"); } if (TT.getArch() == llvm::Triple::arm || TT.getArch() == llvm::Triple::thumb) { if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) { if (A->getOption().matches(options::OPT_mlong_calls)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-long-calls"); } } } // Forward -f options with positive and negative forms; we translate // these by hand. if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { StringRef fname = A->getValue(); if (!llvm::sys::fs::exists(fname)) D.Diag(diag::err_drv_no_such_file) << fname; else A->render(Args, CmdArgs); } if (Args.hasArg(options::OPT_mkernel)) { if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType)) CmdArgs.push_back("-fapple-kext"); if (!Args.hasArg(options::OPT_fbuiltin)) CmdArgs.push_back("-fno-builtin"); Args.ClaimAllArgs(options::OPT_fno_builtin); } // -fbuiltin is default. else if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) CmdArgs.push_back("-fno-builtin"); if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, getToolChain().IsBlocksDefault()) || (Args.hasArg(options::OPT_fgnu_runtime) && Args.hasArg(options::OPT_fobjc_nonfragile_abi) && !Args.hasArg(options::OPT_fno_blocks))) { CmdArgs.push_back("-fblocks"); if (!Args.hasArg(options::OPT_fgnu_runtime) && !getToolChain().hasBlocksRuntime()) CmdArgs.push_back("-fblocks-runtime-optional"); } // -fmodules enables modules (off by default). // Users can pass -fno-cxx-modules to turn off modules support for // C++/Objective-C++ programs, which is a little less mature. bool HaveModules = false; if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, options::OPT_fno_cxx_modules, true); if (AllowedInCXX || !types::isCXX(InputType)) { CmdArgs.push_back("-fmodules"); HaveModules = true; } } // -fmodule-maps enables module map processing (off by default) for header // checking. It is implied by -fmodules. if (Args.hasFlag(options::OPT_fmodule_maps, options::OPT_fno_module_maps, false)) { CmdArgs.push_back("-fmodule-maps"); } // -fmodules-decluse checks that modules used are declared so (off by // default). if (Args.hasFlag(options::OPT_fmodules_decluse, options::OPT_fno_modules_decluse, false)) { CmdArgs.push_back("-fmodules-decluse"); } // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that // all #included headers are part of modules. if (Args.hasFlag(options::OPT_fmodules_strict_decluse, options::OPT_fno_modules_strict_decluse, false)) { CmdArgs.push_back("-fmodules-strict-decluse"); } // -fmodule-name specifies the module that is currently being built (or // used for header checking by -fmodule-maps). Args.AddLastArg(CmdArgs, options::OPT_fmodule_name); // -fmodule-map-file can be used to specify files containing module // definitions. Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); // -fmodule-file can be used to specify files containing precompiled modules. Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); // -fmodule-cache-path specifies where our implicitly-built module files // should be written. SmallString<128> ModuleCachePath; if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) ModuleCachePath = A->getValue(); if (HaveModules) { if (C.isForDiagnostics()) { // When generating crash reports, we want to emit the modules along with // the reproduction sources, so we ignore any provided module path. ModuleCachePath = Output.getFilename(); llvm::sys::path::replace_extension(ModuleCachePath, ".cache"); llvm::sys::path::append(ModuleCachePath, "modules"); } else if (ModuleCachePath.empty()) { // No module path was provided: use the default. llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, ModuleCachePath); llvm::sys::path::append(ModuleCachePath, "org.llvm.clang"); llvm::sys::path::append(ModuleCachePath, "ModuleCache"); } const char Arg[] = "-fmodules-cache-path="; ModuleCachePath.insert(ModuleCachePath.begin(), Arg, Arg + strlen(Arg)); CmdArgs.push_back(Args.MakeArgString(ModuleCachePath)); } // When building modules and generating crashdumps, we need to dump a module // dependency VFS alongside the output. if (HaveModules && C.isForDiagnostics()) { SmallString<128> VFSDir(Output.getFilename()); llvm::sys::path::replace_extension(VFSDir, ".cache"); // Add the cache directory as a temp so the crash diagnostics pick it up. C.addTempFile(Args.MakeArgString(VFSDir)); llvm::sys::path::append(VFSDir, "vfs"); CmdArgs.push_back("-module-dependency-dir"); CmdArgs.push_back(Args.MakeArgString(VFSDir)); } if (HaveModules) Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); // Pass through all -fmodules-ignore-macro arguments. Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { if (Args.hasArg(options::OPT_fbuild_session_timestamp)) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-fbuild-session-timestamp"; llvm::sys::fs::file_status Status; if (llvm::sys::fs::status(A->getValue(), Status)) D.Diag(diag::err_drv_no_such_file) << A->getValue(); char TimeStamp[48]; snprintf(TimeStamp, sizeof(TimeStamp), "-fbuild-session-timestamp=%" PRIu64, (uint64_t)Status.getLastModificationTime().toEpochTime()); CmdArgs.push_back(Args.MakeArgString(TimeStamp)); } if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, options::OPT_fbuild_session_file)) D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_once_per_build_session); } Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, options::OPT_faccess_control, false)) CmdArgs.push_back("-fno-access-control"); // -felide-constructors is the default. if (Args.hasFlag(options::OPT_fno_elide_constructors, options::OPT_felide_constructors, false)) CmdArgs.push_back("-fno-elide-constructors"); // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) || KernelOrKext) { CmdArgs.push_back("-fno-rtti"); // -fno-rtti cannot usefully be combined with -fsanitize=vptr. if (Sanitize.sanitizesVptr()) { std::string NoRttiArg = Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext, options::OPT_fno_rtti)->getAsString(Args); D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize=vptr" << NoRttiArg; } } // -fshort-enums=0 is default for all architectures except Hexagon. if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, getToolChain().getArch() == llvm::Triple::hexagon)) CmdArgs.push_back("-fshort-enums"); // -fsigned-char is default. if (!Args.hasFlag(options::OPT_fsigned_char, options::OPT_funsigned_char, isSignedCharDefault(getToolChain().getTriple()))) CmdArgs.push_back("-fno-signed-char"); // -fthreadsafe-static is default. if (!Args.hasFlag(options::OPT_fthreadsafe_statics, options::OPT_fno_threadsafe_statics)) CmdArgs.push_back("-fno-threadsafe-statics"); // -fuse-cxa-atexit is default. if (!Args.hasFlag(options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, !IsWindowsCygnus && !IsWindowsGNU && getToolChain().getArch() != llvm::Triple::hexagon && getToolChain().getArch() != llvm::Triple::xcore) || KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) CmdArgs.push_back("-fms-extensions"); // -fms-compatibility=0 is default. if (Args.hasFlag(options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, true)))) CmdArgs.push_back("-fms-compatibility"); // -fms-compatibility-version=17.00 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC) || Args.hasArg(options::OPT_fmsc_version) || Args.hasArg(options::OPT_fms_compatibility_version)) { const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version); const Arg *MSCompatibilityVersion = Args.getLastArg(options::OPT_fms_compatibility_version); if (MSCVersion && MSCompatibilityVersion) D.Diag(diag::err_drv_argument_not_allowed_with) << MSCVersion->getAsString(Args) << MSCompatibilityVersion->getAsString(Args); std::string Ver; if (MSCompatibilityVersion) Ver = Args.getLastArgValue(options::OPT_fms_compatibility_version); else if (MSCVersion) Ver = getMSCompatibilityVersion(MSCVersion->getValue()); if (Ver.empty()) CmdArgs.push_back("-fms-compatibility-version=17.00"); else CmdArgs.push_back(Args.MakeArgString("-fms-compatibility-version=" + Ver)); } // -fno-borland-extensions is default. if (Args.hasFlag(options::OPT_fborland_extensions, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); // -fno-delayed-template-parsing is default, except for Windows where MSVC STL // needs it. if (Args.hasFlag(options::OPT_fdelayed_template_parsing, options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) CmdArgs.push_back("-fdelayed-template-parsing"); // -fgnu-keywords default varies depending on language; only pass if // specified. if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, options::OPT_fno_gnu_keywords)) A->render(Args, CmdArgs); if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, false)) CmdArgs.push_back("-fgnu89-inline"); if (Args.hasArg(options::OPT_fno_inline)) CmdArgs.push_back("-fno-inline"); if (Args.hasArg(options::OPT_fno_inline_functions)) CmdArgs.push_back("-fno-inline-functions"); ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and // legacy is the default. Except for deployment taget of 10.5, // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch // gets ignored silently. if (objcRuntime.isNonFragile()) { if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, options::OPT_fno_objc_legacy_dispatch, objcRuntime.isLegacyDispatchDefaultForArch( getToolChain().getArch()))) { if (getToolChain().UseObjCMixedDispatch()) CmdArgs.push_back("-fobjc-dispatch-method=mixed"); else CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); } } // When ObjectiveC legacy runtime is in effect on MacOSX, // turn on the option to do Array/Dictionary subscripting // by default. if (getToolChain().getTriple().getArch() == llvm::Triple::x86 && getToolChain().getTriple().isMacOSX() && !getToolChain().getTriple().isMacOSXVersionLT(10, 7) && objcRuntime.getKind() == ObjCRuntime::FragileMacOSX && objcRuntime.isNeXTFamily()) CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); // -fencode-extended-block-signature=1 is default. if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) { CmdArgs.push_back("-fencode-extended-block-signature"); } // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. // NOTE: This logic is duplicated in ToolChains.cpp. bool ARC = isObjCAutoRefCount(Args); if (ARC) { getToolChain().CheckObjCARC(); CmdArgs.push_back("-fobjc-arc"); // FIXME: It seems like this entire block, and several around it should be // wrapped in isObjC, but for now we just use it here as this is where it // was being used previously. if (types::isCXX(InputType) && types::isObjC(InputType)) { if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); else CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); } // Allow the user to enable full exceptions code emission. // We define off for Objective-CC, on for Objective-C++. if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, options::OPT_fno_objc_arc_exceptions, /*default*/ types::isCXX(InputType))) CmdArgs.push_back("-fobjc-arc-exceptions"); } // -fobjc-infer-related-result-type is the default, except in the Objective-C // rewriter. if (rewriteKind != RK_None) CmdArgs.push_back("-fno-objc-infer-related-result-type"); // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only // takes precedence. const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); if (!GCArg) GCArg = Args.getLastArg(options::OPT_fobjc_gc); if (GCArg) { if (ARC) { D.Diag(diag::err_drv_objc_gc_arr) << GCArg->getAsString(Args); } else if (getToolChain().SupportsObjCGC()) { GCArg->render(Args, CmdArgs); } else { // FIXME: We should move this to a hard error. D.Diag(diag::warn_drv_objc_gc_unsupported) << GCArg->getAsString(Args); } } // Handle GCC-style exception args. if (!C.getDriver().IsCLMode()) addExceptionArgs(Args, InputType, getToolChain().getTriple(), KernelOrKext, objcRuntime, CmdArgs); if (getToolChain().UseSjLjExceptions()) CmdArgs.push_back("-fsjlj-exceptions"); // C++ "sane" operator new. if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); // -fconstant-cfstrings is default, and may be subject to argument translation // on Darwin. if (!Args.hasFlag(options::OPT_fconstant_cfstrings, options::OPT_fno_constant_cfstrings) || !Args.hasFlag(options::OPT_mconstant_cfstrings, options::OPT_mno_constant_cfstrings)) CmdArgs.push_back("-fno-constant-cfstrings"); // -fshort-wchar default varies depending on platform; only // pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar, options::OPT_fno_short_wchar)) A->render(Args, CmdArgs); // -fno-pascal-strings is default, only pass non-default. if (Args.hasFlag(options::OPT_fpascal_strings, options::OPT_fno_pascal_strings, false)) CmdArgs.push_back("-fpascal-strings"); // Honor -fpack-struct= and -fpack-struct, if given. Note that // -fno-pack-struct doesn't apply to -fpack-struct=. if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { std::string PackStructStr = "-fpack-struct="; PackStructStr += A->getValue(); CmdArgs.push_back(Args.MakeArgString(PackStructStr)); } else if (Args.hasFlag(options::OPT_fpack_struct, options::OPT_fno_pack_struct, false)) { CmdArgs.push_back("-fpack-struct=1"); } // Handle -fmax-type-align=N and -fno-type-align bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align); if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) { if (!SkipMaxTypeAlign) { std::string MaxTypeAlignStr = "-fmax-type-align="; MaxTypeAlignStr += A->getValue(); CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); } } else if (getToolChain().getTriple().isOSDarwin()) { if (!SkipMaxTypeAlign) { std::string MaxTypeAlignStr = "-fmax-type-align=16"; CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); } } if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); Args.ClaimAllArgs(options::OPT_fno_common); } // -fcommon is default, only pass non-default. else if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common)) CmdArgs.push_back("-fno-common"); // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, options::OPT_funsigned_bitfields)) D.Diag(diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) D.Diag(diag::err_drv_clang_unsupported) << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); // -finput_charset=UTF-8 is default. Reject others if (Arg *inputCharset = Args.getLastArg( options::OPT_finput_charset_EQ)) { StringRef value = inputCharset->getValue(); if (value != "UTF-8") D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) << value; } // -fexec_charset=UTF-8 is default. Reject others if (Arg *execCharset = Args.getLastArg( options::OPT_fexec_charset_EQ)) { StringRef value = execCharset->getValue(); if (value != "UTF-8") D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) << value; } // -fcaret-diagnostics is default. if (!Args.hasFlag(options::OPT_fcaret_diagnostics, options::OPT_fno_caret_diagnostics, true)) CmdArgs.push_back("-fno-caret-diagnostics"); // -fdiagnostics-fixit-info is default, only pass non-default. if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); // Enable -fdiagnostics-show-option by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { CmdArgs.push_back("-fdiagnostics-show-category"); CmdArgs.push_back(A->getValue()); } if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg( options::OPT_fdiagnostics_show_note_include_stack, options::OPT_fno_diagnostics_show_note_include_stack)) { if (A->getOption().matches( options::OPT_fdiagnostics_show_note_include_stack)) CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); else CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); } // Color diagnostics are the default, unless the terminal doesn't support // them. // Support both clang's -f[no-]color-diagnostics and gcc's // -f[no-]diagnostics-colors[=never|always|auto]. enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto; for (const auto &Arg : Args) { const Option &O = Arg->getOption(); if (!O.matches(options::OPT_fcolor_diagnostics) && !O.matches(options::OPT_fdiagnostics_color) && !O.matches(options::OPT_fno_color_diagnostics) && !O.matches(options::OPT_fno_diagnostics_color) && !O.matches(options::OPT_fdiagnostics_color_EQ)) continue; Arg->claim(); if (O.matches(options::OPT_fcolor_diagnostics) || O.matches(options::OPT_fdiagnostics_color)) { ShowColors = Colors_On; } else if (O.matches(options::OPT_fno_color_diagnostics) || O.matches(options::OPT_fno_diagnostics_color)) { ShowColors = Colors_Off; } else { assert(O.matches(options::OPT_fdiagnostics_color_EQ)); StringRef value(Arg->getValue()); if (value == "always") ShowColors = Colors_On; else if (value == "never") ShowColors = Colors_Off; else if (value == "auto") ShowColors = Colors_Auto; else getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << ("-fdiagnostics-color=" + value).str(); } } if (ShowColors == Colors_On || (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors())) CmdArgs.push_back("-fcolor-diagnostics"); if (Args.hasArg(options::OPT_fansi_escape_codes)) CmdArgs.push_back("-fansi-escape-codes"); if (!Args.hasFlag(options::OPT_fshow_source_location, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, true)) CmdArgs.push_back("-fno-show-column"); if (!Args.hasFlag(options::OPT_fspell_checking, options::OPT_fno_spell_checking)) CmdArgs.push_back("-fno-spell-checking"); // -fno-asm-blocks is default. if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, false)) CmdArgs.push_back("-fasm-blocks"); // Enable vectorization per default according to the optimization level // selected. For optimization levels that want vectorization we use the alias // option to simplify the hasFlag logic. bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false); OptSpecifier VectorizeAliasOption = EnableVec ? options::OPT_O_Group : options::OPT_fvectorize; if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, options::OPT_fno_vectorize, EnableVec)) CmdArgs.push_back("-vectorize-loops"); // -fslp-vectorize is enabled based on the optimization level selected. bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true); OptSpecifier SLPVectAliasOption = EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize; if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption, options::OPT_fno_slp_vectorize, EnableSLPVec)) CmdArgs.push_back("-vectorize-slp"); // -fno-slp-vectorize-aggressive is default. if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, options::OPT_fno_slp_vectorize_aggressive, false)) CmdArgs.push_back("-vectorize-slp-aggressive"); if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, options::OPT_fno_dollars_in_identifiers)) { if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) CmdArgs.push_back("-fdollars-in-identifiers"); else CmdArgs.push_back("-fno-dollars-in-identifiers"); } // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for // practical purposes. if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, options::OPT_fno_unit_at_a_time)) { if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); } if (Args.hasFlag(options::OPT_fapple_pragma_pack, options::OPT_fno_apple_pragma_pack, false)) CmdArgs.push_back("-fapple-pragma-pack"); // le32-specific flags: // -fno-math-builtin: clang should not convert math builtins to intrinsics // by default. if (getToolChain().getArch() == llvm::Triple::le32) { CmdArgs.push_back("-fno-math-builtin"); } // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 if (getToolChain().getTriple().isOSDarwin() && (getToolChain().getArch() == llvm::Triple::arm || getToolChain().getArch() == llvm::Triple::thumb)) { if (!Args.hasArg(options::OPT_fbuiltin_strcat)) CmdArgs.push_back("-fno-builtin-strcat"); if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) CmdArgs.push_back("-fno-builtin-strcpy"); } #endif // Enable rewrite includes if the user's asked for it or if we're generating // diagnostics. // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || (C.isForDiagnostics() && !HaveModules)) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. if (Arg *A = Args.getLastArg(options::OPT_traditional, options::OPT_traditional_cpp)) { if (isa(JA)) CmdArgs.push_back("-traditional-cpp"); else D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); } Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); // Handle serialized diagnostics. if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { CmdArgs.push_back("-serialize-diagnostic-file"); CmdArgs.push_back(Args.MakeArgString(A->getValue())); } if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) CmdArgs.push_back("-fretain-comments-from-system-headers"); // Forward -fcomment-block-commands to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); // Forward -fparse-all-comments to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); bool OptDisabled = false; for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm), ie = Args.filtered_end(); it != ie; ++it) { (*it)->claim(); // We translate this by hand to the -cc1 argument, since nightly test uses // it and developers have been trained to spell it with -mllvm. if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns") { CmdArgs.push_back("-disable-llvm-optzns"); OptDisabled = true; } else (*it)->render(Args, CmdArgs); } // With -save-temps, we want to save the unoptimized bitcode output from the // CompileJobAction, so disable optimizations if they are not already // disabled. if (Args.hasArg(options::OPT_save_temps) && !OptDisabled && isa(JA)) CmdArgs.push_back("-disable-llvm-optzns"); if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. } else if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } for (const auto &II : Inputs) { addDashXForInput(Args, II, CmdArgs); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_undef); const char *Exec = getToolChain().getDriver().getClangProgramPath(); // Optionally embed the -cc1 level arguments into the debug info, for build // analysis. if (getToolChain().UseDwarfDebugFlags()) { ArgStringList OriginalArgs; for (const auto &Arg : Args) Arg->render(Args, OriginalArgs); SmallString<256> Flags; Flags += Exec; for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) { SmallString<128> EscapedArg; EscapeSpacesAndBackslashes(OriginalArgs[i], EscapedArg); Flags += " "; Flags += EscapedArg; } CmdArgs.push_back("-dwarf-debug-flags"); CmdArgs.push_back(Args.MakeArgString(Flags.str())); } // Add the split debug info name to the command lines here so we // can propagate it to the backend. bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) && getToolChain().getTriple().isOSLinux() && (isa(JA) || isa(JA) || isa(JA)); const char *SplitDwarfOut; if (SplitDwarf) { CmdArgs.push_back("-split-dwarf-file"); SplitDwarfOut = SplitDebugName(Args, Inputs); CmdArgs.push_back(SplitDwarfOut); } // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && (InputType == types::TY_C || InputType == types::TY_CXX)) { auto CLCommand = getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, std::move(CLCommand))); } else { C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. if (SplitDwarf && !isa(JA) && !isa(JA)) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut); if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" << A->getAsString(Args); // Claim some arguments which clang supports automatically. // -fpch-preprocess is used with gcc to add a special marker in the output to // include the PCH file. Clang's PTH solution is completely transparent, so we // do not need to deal with it at all. Args.ClaimAllArgs(options::OPT_fpch_preprocess); // Claim some arguments which clang doesn't support, but we don't // care to warn the user about. Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); // Disable warnings for clang -E -emit-llvm foo.c Args.ClaimAllArgs(options::OPT_emit_llvm); } /// Add options related to the Objective-C runtime/ABI. /// /// Returns true if the runtime is non-fragile. ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, ArgStringList &cmdArgs, RewriteKind rewriteKind) const { // Look for the controlling runtime option. Arg *runtimeArg = args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, options::OPT_fobjc_runtime_EQ); // Just forward -fobjc-runtime= to the frontend. This supercedes // options about fragility. if (runtimeArg && runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { ObjCRuntime runtime; StringRef value = runtimeArg->getValue(); if (runtime.tryParse(value)) { getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) << value; } runtimeArg->render(args, cmdArgs); return runtime; } // Otherwise, we'll need the ABI "version". Version numbers are // slightly confusing for historical reasons: // 1 - Traditional "fragile" ABI // 2 - Non-fragile ABI, version 1 // 3 - Non-fragile ABI, version 2 unsigned objcABIVersion = 1; // If -fobjc-abi-version= is present, use that to set the version. if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { StringRef value = abiArg->getValue(); if (value == "1") objcABIVersion = 1; else if (value == "2") objcABIVersion = 2; else if (value == "3") objcABIVersion = 3; else getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value; } else { // Otherwise, determine if we are using the non-fragile ABI. bool nonFragileABIIsDefault = (rewriteKind == RK_NonFragile || (rewriteKind == RK_None && getToolChain().IsObjCNonFragileABIDefault())); if (args.hasFlag(options::OPT_fobjc_nonfragile_abi, options::OPT_fno_objc_nonfragile_abi, nonFragileABIIsDefault)) { // Determine the non-fragile ABI version to use. #ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO unsigned nonFragileABIVersion = 1; #else unsigned nonFragileABIVersion = 2; #endif if (Arg *abiArg = args.getLastArg( options::OPT_fobjc_nonfragile_abi_version_EQ)) { StringRef value = abiArg->getValue(); if (value == "1") nonFragileABIVersion = 1; else if (value == "2") nonFragileABIVersion = 2; else getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value; } objcABIVersion = 1 + nonFragileABIVersion; } else { objcABIVersion = 1; } } // We don't actually care about the ABI version other than whether // it's non-fragile. bool isNonFragile = objcABIVersion != 1; // If we have no runtime argument, ask the toolchain for its default runtime. // However, the rewriter only really supports the Mac runtime, so assume that. ObjCRuntime runtime; if (!runtimeArg) { switch (rewriteKind) { case RK_None: runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); break; case RK_Fragile: runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple()); break; case RK_NonFragile: runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); break; } // -fnext-runtime } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) { // On Darwin, make this use the default behavior for the toolchain. if (getToolChain().getTriple().isOSDarwin()) { runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); // Otherwise, build for a generic macosx port. } else { runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); } // -fgnu-runtime } else { assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); // Legacy behaviour is to target the gnustep runtime if we are i // non-fragile mode or the GCC runtime in fragile mode. if (isNonFragile) runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1,6)); else runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } cmdArgs.push_back(args.MakeArgString( "-fobjc-runtime=" + runtime.getAsString())); return runtime; } static bool maybeConsumeDash(const std::string &EH, size_t &I) { bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-'); I += HaveDash; return !HaveDash; } struct EHFlags { EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {} bool Synch; bool Asynch; bool NoExceptC; }; /// /EH controls whether to run destructor cleanups when exceptions are /// thrown. There are three modifiers: /// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions. /// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions. /// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR. /// - c: Assume that extern "C" functions are implicitly noexcept. This /// modifier is an optimization, so we ignore it for now. /// The default is /EHs-c-, meaning cleanups are disabled. static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { EHFlags EH; std::vector EHArgs = Args.getAllArgValues(options::OPT__SLASH_EH); for (auto EHVal : EHArgs) { for (size_t I = 0, E = EHVal.size(); I != E; ++I) { switch (EHVal[I]) { case 'a': EH.Asynch = maybeConsumeDash(EHVal, I); continue; case 'c': EH.NoExceptC = maybeConsumeDash(EHVal, I); continue; case 's': EH.Synch = maybeConsumeDash(EHVal, I); continue; default: break; } D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal; break; } } return EH; } void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const { unsigned RTOptionID = options::OPT__SLASH_MT; if (Args.hasArg(options::OPT__SLASH_LDd)) // The /LDd option implies /MTd. The dependent lib part can be overridden, // but defining _DEBUG is sticky. RTOptionID = options::OPT__SLASH_MTd; if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) RTOptionID = A->getOption().getID(); switch(RTOptionID) { case options::OPT__SLASH_MD: if (Args.hasArg(options::OPT__SLASH_LDd)) CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DLL"); CmdArgs.push_back("--dependent-lib=msvcrt"); break; case options::OPT__SLASH_MDd: CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("-D_DLL"); CmdArgs.push_back("--dependent-lib=msvcrtd"); break; case options::OPT__SLASH_MT: if (Args.hasArg(options::OPT__SLASH_LDd)) CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("--dependent-lib=libcmt"); break; case options::OPT__SLASH_MTd: CmdArgs.push_back("-D_DEBUG"); CmdArgs.push_back("-D_MT"); CmdArgs.push_back("--dependent-lib=libcmtd"); break; default: llvm_unreachable("Unexpected option ID."); } // This provides POSIX compatibility (maps 'open' to '_open'), which most // users want. The /Za flag to cl.exe turns this off, but it's not // implemented in clang. CmdArgs.push_back("--dependent-lib=oldnames"); // Both /showIncludes and /E (and /EP) write to stdout. Allowing both // would produce interleaved output, so ignore /showIncludes in such cases. if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) if (Arg *A = Args.getLastArg(options::OPT_show_includes)) A->render(Args, CmdArgs); // This controls whether or not we emit RTTI data for polymorphic types. if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, /*default=*/false)) CmdArgs.push_back("-fno-rtti-data"); const Driver &D = getToolChain().getDriver(); EHFlags EH = parseClangCLEHFlags(D, Args); // FIXME: Do something with NoExceptC. if (EH.Synch || EH.Asynch) { CmdArgs.push_back("-fexceptions"); CmdArgs.push_back("-fcxx-exceptions"); } // /EP should expand to -E -P. if (Args.hasArg(options::OPT__SLASH_EP)) { CmdArgs.push_back("-E"); CmdArgs.push_back("-P"); } Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); if (MostGeneralArg && BestCaseArg) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args); if (MostGeneralArg) { Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms); Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm); Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv); Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg; Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg; if (FirstConflict && SecondConflict && FirstConflict != SecondConflict) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << FirstConflict->getAsString(Args) << SecondConflict->getAsString(Args); if (SingleArg) CmdArgs.push_back("-fms-memptr-rep=single"); else if (MultipleArg) CmdArgs.push_back("-fms-memptr-rep=multiple"); else CmdArgs.push_back("-fms-memptr-rep=virtual"); } if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ)) A->render(Args, CmdArgs); if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); if (Args.hasArg(options::OPT__SLASH_fallback)) CmdArgs.push_back("msvc-fallback"); else CmdArgs.push_back("msvc"); } } visualstudio::Compile *Clang::getCLFallback() const { if (!CLFallback) CLFallback.reset(new visualstudio::Compile(getToolChain())); return CLFallback.get(); } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); // and "clang -emit-llvm -c foo.s" Args.ClaimAllArgs(options::OPT_emit_llvm); claimNoWarnArgs(Args); // Invoke ourselves in -cc1as mode. // // FIXME: Implement custom jobs for internal actions. CmdArgs.push_back("-cc1as"); // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args, Input.getType()); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Set the output mode, we currently only expect to be used as a real // assembler. CmdArgs.push_back("-filetype"); CmdArgs.push_back("obj"); // Set the main file name, so that debug info works even with // -save-temps or preprocessed assembly. CmdArgs.push_back("-main-file-name"); CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs)); // Add the target cpu const llvm::Triple &Triple = getToolChain().getTriple(); std::string CPU = getCPUName(Args, Triple); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); } // Add the target features const Driver &D = getToolChain().getDriver(); getTargetFeatures(D, Triple, Args, CmdArgs, true); // Ignore explicit -force_cpusubtype_ALL option. (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); // Determine the original source input. const Action *SourceAction = &JA; while (SourceAction->getKind() != Action::InputClass) { assert(!SourceAction->getInputs().empty() && "unexpected root action!"); SourceAction = SourceAction->getInputs()[0]; } // Forward -g and handle debug info related flags, assuming we are dealing // with an actual assembly file. if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { Args.ClaimAllArgs(options::OPT_g_Group); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) if (!A->getOption().matches(options::OPT_g0)) CmdArgs.push_back("-g"); if (Args.hasArg(options::OPT_gdwarf_2)) CmdArgs.push_back("-gdwarf-2"); if (Args.hasArg(options::OPT_gdwarf_3)) CmdArgs.push_back("-gdwarf-3"); if (Args.hasArg(options::OPT_gdwarf_4)) CmdArgs.push_back("-gdwarf-4"); // Add the -fdebug-compilation-dir flag if needed. addDebugCompDirArg(Args, CmdArgs); // Set the AT_producer to the clang version when using the integrated // assembler on assembly source files. CmdArgs.push_back("-dwarf-debug-producer"); CmdArgs.push_back(Args.MakeArgString(getClangFullVersion())); } // Optionally embed the -cc1as level arguments into the debug info, for build // analysis. if (getToolChain().UseDwarfDebugFlags()) { ArgStringList OriginalArgs; for (const auto &Arg : Args) Arg->render(Args, OriginalArgs); SmallString<256> Flags; const char *Exec = getToolChain().getDriver().getClangProgramPath(); Flags += Exec; for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) { SmallString<128> EscapedArg; EscapeSpacesAndBackslashes(OriginalArgs[i], EscapedArg); Flags += " "; Flags += EscapedArg; } CmdArgs.push_back("-dwarf-debug-flags"); CmdArgs.push_back(Args.MakeArgString(Flags.str())); } // FIXME: Add -static support, once we have it. // Consume all the warning flags. Usually this would be handled more // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as // doesn't handle that so rather than warning about unused flags that are // actually used, we'll lie by omission instead. // FIXME: Stop lying and consume only the appropriate driver flags for (arg_iterator it = Args.filtered_begin(options::OPT_W_Group), ie = Args.filtered_end(); it != ie; ++it) (*it)->claim(); CollectArgsForIntegratedAssembler(C, Args, CmdArgs, getToolChain().getDriver()); Args.AddAllArgs(CmdArgs, options::OPT_mllvm); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. if (Args.hasArg(options::OPT_gsplit_dwarf) && getToolChain().getTriple().isOSLinux()) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDebugName(Args, Inputs)); } void GnuTool::anchor() {} void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; for (const auto &A : Args) { if (forwardToGCC(A->getOption())) { // Don't forward any -g arguments to assembly steps. if (isa(JA) && A->getOption().matches(options::OPT_g_Group)) continue; // Don't forward any -W arguments to assembly and link steps. if ((isa(JA) || isa(JA)) && A->getOption().matches(options::OPT_W_Group)) continue; // It is unfortunate that we have to claim here, as this means // we will basically never report anything interesting for // platforms using a generic gcc, even if we are just using gcc // to get to the assembler. A->claim(); A->render(Args, CmdArgs); } } RenderExtraToolArgs(JA, CmdArgs); // If using a driver driver, force the arch. if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); CmdArgs.push_back( Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); } // Try to force gcc to match the tool chain we want, if we recognize // the arch. // // FIXME: The triple class should directly provide the information we want // here. llvm::Triple::ArchType Arch = getToolChain().getArch(); if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) CmdArgs.push_back("-m32"); else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64 || Arch == llvm::Triple::ppc64le) CmdArgs.push_back("-m64"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); // Only pass -x if gcc will understand it; otherwise hope gcc // understands the suffix correctly. The main use case this would go // wrong in is for linker inputs if they happened to have an odd // suffix; really the only way to get this to happen is a command // like '-x foobar a.c' which will treat a.c like a linker input. // // FIXME: For the linker case specifically, can we safely convert // inputs into '-Wl,' options? for (const auto &II : Inputs) { // Don't try to pass LLVM or AST inputs to a generic gcc. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) D.Diag(diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_ModuleFile) D.Diag(diag::err_drv_no_module_support) << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); CmdArgs.push_back(types::getTypeName(II.getType())); } if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else { const Arg &A = II.getInputArg(); // Reverse translate some rewritten options. if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { CmdArgs.push_back("-lstdc++"); continue; } // Don't render as input, we need gcc to do the translations. A.render(Args, CmdArgs); } } const std::string customGCCName = D.getCCCGenericGCCName(); const char *GCCName; if (!customGCCName.empty()) GCCName = customGCCName.c_str(); else if (D.CCCIsCXX()) { GCCName = "g++"; } else GCCName = "gcc"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { CmdArgs.push_back("-E"); } void gcc::Compile::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); // If -flto, etc. are present then make sure not to force assembly output. if (JA.getType() == types::TY_LLVM_IR || JA.getType() == types::TY_LTO_IR || JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) CmdArgs.push_back("-c"); else { if (JA.getType() != types::TY_PP_Asm) D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); CmdArgs.push_back("-S"); } } void gcc::Link::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { // The types are (hopefully) good enough. } // Hexagon tools start. void hexagon::Assemble::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { } void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; std::string MarchString = "-march="; MarchString += toolchains::Hexagon_TC::GetTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString(MarchString)); RenderExtraToolArgs(JA, CmdArgs); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Unexpected output"); CmdArgs.push_back("-fsyntax-only"); } std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); if (!SmallDataThreshold.empty()) CmdArgs.push_back( Args.MakeArgString(std::string("-G") + SmallDataThreshold)); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); // Only pass -x if gcc will understand it; otherwise hope gcc // understands the suffix correctly. The main use case this would go // wrong in is for linker inputs if they happened to have an odd // suffix; really the only way to get this to happen is a command // like '-x foobar a.c' which will treat a.c like a linker input. // // FIXME: For the linker case specifically, can we safely convert // inputs into '-Wl,' options? for (const auto &II : Inputs) { // Don't try to pass LLVM or AST inputs to a generic gcc. if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR || II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC) D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_AST) D.Diag(clang::diag::err_drv_no_ast_support) << getToolChain().getTripleString(); else if (II.getType() == types::TY_ModuleFile) D.Diag(diag::err_drv_no_module_support) << getToolChain().getTripleString(); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ? II.getInputArg().render(Args, CmdArgs); } const char *GCCName = "hexagon-as"; const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void hexagon::Link::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { // The types are (hopefully) good enough. } void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::Hexagon_TC& ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- bool hasStaticArg = Args.hasArg(options::OPT_static); bool buildingLib = Args.hasArg(options::OPT_shared); bool buildPIE = Args.hasArg(options::OPT_pie); bool incStdLib = !Args.hasArg(options::OPT_nostdlib); bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); bool useShared = buildingLib && !hasStaticArg; //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- Args.ClaimAllArgs(options::OPT_g_Group); Args.ClaimAllArgs(options::OPT_emit_llvm); Args.ClaimAllArgs(options::OPT_w); // Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_static_libgcc); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString("-m" + MarchString)); if (buildingLib) { CmdArgs.push_back("-shared"); CmdArgs.push_back("-call_shared"); // should be the default, but doing as // hexagon-gcc does } if (hasStaticArg) CmdArgs.push_back("-static"); if (buildPIE && !buildingLib) CmdArgs.push_back("-pie"); std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args); if (!SmallDataThreshold.empty()) { CmdArgs.push_back( Args.MakeArgString(std::string("-G") + SmallDataThreshold)); } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); const std::string MarchSuffix = "/" + MarchString; const std::string G0Suffix = "/G0"; const std::string MarchG0Suffix = MarchSuffix + G0Suffix; const std::string RootDir = toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir, Args) + "/"; const std::string StartFilesDir = RootDir + "hexagon/lib" + (buildingLib ? MarchG0Suffix : MarchSuffix); //---------------------------------------------------------------------------- // moslib //---------------------------------------------------------------------------- std::vector oslibs; bool hasStandalone= false; for (arg_iterator it = Args.filtered_begin(options::OPT_moslib_EQ), ie = Args.filtered_end(); it != ie; ++it) { (*it)->claim(); oslibs.push_back((*it)->getValue()); hasStandalone = hasStandalone || (oslibs.back() == "standalone"); } if (oslibs.empty()) { oslibs.push_back("standalone"); hasStandalone = true; } //---------------------------------------------------------------------------- // Start Files //---------------------------------------------------------------------------- if (incStdLib && incStartFiles) { if (!buildingLib) { if (hasStandalone) { CmdArgs.push_back( Args.MakeArgString(StartFilesDir + "/crt0_standalone.o")); } CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o")); } std::string initObj = useShared ? "/initS.o" : "/init.o"; CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj)); } //---------------------------------------------------------------------------- // Library Search Paths //---------------------------------------------------------------------------- const ToolChain::path_list &LibPaths = ToolChain.getFilePaths(); for (const auto &LibPath : LibPaths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); //---------------------------------------------------------------------------- // Libraries //---------------------------------------------------------------------------- if (incStdLib && incDefLibs) { if (D.CCCIsCXX()) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } CmdArgs.push_back("--start-group"); if (!buildingLib) { for(std::vector::iterator i = oslibs.begin(), e = oslibs.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString("-l" + *i)); CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--end-group"); } //---------------------------------------------------------------------------- // End files //---------------------------------------------------------------------------- if (incStdLib && incStartFiles) { std::string finiObj = useShared ? "/finiS.o" : "/fini.o"; CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj)); } std::string Linker = ToolChain.GetProgramPath("hexagon-ld"); C.addCommand(llvm::make_unique(JA, *this, Args.MakeArgString(Linker), CmdArgs)); } // Hexagon tools end. /// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. const char *arm::getARMCPUForMArch(const ArgList &Args, const llvm::Triple &Triple) { StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. MArch = A->getValue(); } else { // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); } // Handle -march=native. if (MArch == "native") { std::string CPU = llvm::sys::getHostCPUName(); if (CPU != "generic") { // Translate the native cpu into the architecture. The switch below will // then chose the minimum cpu for that arch. MArch = std::string("arm") + arm::getLLVMArchSuffixForARM(CPU); } } return Triple.getARMCPUForArch(MArch); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. StringRef arm::getARMTargetCPU(const ArgList &Args, const llvm::Triple &Triple) { // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { StringRef MCPU = A->getValue(); // Handle -mcpu=native. if (MCPU == "native") return llvm::sys::getHostCPUName(); else return MCPU; } return getARMCPUForMArch(Args, Triple); } /// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular /// CPU. // // FIXME: This is redundant with -mcpu, why does LLVM use this. // FIXME: tblgen this, or kill it! const char *arm::getLLVMArchSuffixForARM(StringRef CPU) { return llvm::StringSwitch(CPU) .Case("strongarm", "v4") .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "v4t") .Cases("arm720t", "arm9", "arm9tdmi", "v4t") .Cases("arm920", "arm920t", "arm922t", "v4t") .Cases("arm940t", "ep9312","v4t") .Cases("arm10tdmi", "arm1020t", "v5") .Cases("arm9e", "arm926ej-s", "arm946e-s", "v5e") .Cases("arm966e-s", "arm968e-s", "arm10e", "v5e") .Cases("arm1020e", "arm1022e", "xscale", "iwmmxt", "v5e") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7") .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "v7") .Cases("cortex-r4", "cortex-r5", "v7r") .Case("cortex-m0", "v6m") .Case("cortex-m3", "v7m") .Cases("cortex-m4", "cortex-m7", "v7em") .Case("swift", "v7s") .Case("cyclone", "v8") .Cases("cortex-a53", "cortex-a57", "v8") .Default(""); } void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs, const llvm::Triple &Triple) { if (Args.hasArg(options::OPT_r)) return; StringRef Suffix = getLLVMArchSuffixForARM(getARMCPUForMArch(Args, Triple)); const char *LinkFlag = llvm::StringSwitch(Suffix) .Cases("v4", "v4t", "v5", "v5e", nullptr) .Cases("v6", "v6t2", nullptr) .Default("--be8"); if (LinkFlag) CmdArgs.push_back(LinkFlag); } bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef(Value)); } bool mips::isUCLibc(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_m_libc_Group); return A && A->getOption().matches(options::OPT_muclibc); } bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ)) return llvm::StringSwitch(NaNArg->getValue()) .Case("2008", true) .Case("legacy", false) .Default(false); // NaN2008 is the default for MIPS32r6/MIPS64r6. return llvm::StringSwitch(getCPUName(Args, Triple)) .Cases("mips32r6", "mips64r6", true) .Default(false); return false; } bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName) { if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies && Triple.getVendor() != llvm::Triple::MipsTechnologies) return false; if (ABIName != "32") return false; return llvm::StringSwitch(CPUName) .Cases("mips2", "mips3", "mips4", "mips5", true) .Cases("mips32", "mips32r2", true) .Cases("mips64", "mips64r2", true) .Default(false); } llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for // archs which Darwin doesn't use. // The matching this routine does is fairly pointless, since it is neither the // complete architecture list, nor a reasonable subset. The problem is that // historically the driver driver accepts this and also ties its -march= // handling to the architecture name, so we need to be careful before removing // support for it. // This code must be kept in sync with Clang's Darwin specific argument // translation. return llvm::StringSwitch(Str) .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) .Case("ppc64", llvm::Triple::ppc64) .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", llvm::Triple::x86) .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) // This is derived from the driver driver. .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) .Cases("armv7s", "xscale", llvm::Triple::arm) .Case("arm64", llvm::Triple::aarch64) .Case("r600", llvm::Triple::r600) .Case("amdgcn", llvm::Triple::amdgcn) .Case("nvptx", llvm::Triple::nvptx) .Case("nvptx64", llvm::Triple::nvptx64) .Case("amdil", llvm::Triple::amdil) .Case("spir", llvm::Triple::spir) .Default(llvm::Triple::UnknownArch); } void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); T.setArch(Arch); if (Str == "x86_64h") T.setArchName(Str); else if (Str == "armv6m" || Str == "armv7m" || Str == "armv7em") { T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } } const char *Clang::getBaseInputName(const ArgList &Args, const InputInfoList &Inputs) { return Args.MakeArgString( llvm::sys::path::filename(Inputs[0].getBaseInput())); } const char *Clang::getBaseInputStem(const ArgList &Args, const InputInfoList &Inputs) { const char *Str = getBaseInputName(Args, Inputs); if (const char *End = strrchr(Str, '.')) return Args.MakeArgString(std::string(Str, End)); return Str; } const char *Clang::getDependencyFileName(const ArgList &Args, const InputInfoList &Inputs) { // FIXME: Think about this more. std::string Res; if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { std::string Str(OutputOpt->getValue()); Res = Str.substr(0, Str.rfind('.')); } else { Res = getBaseInputStem(Args, Inputs); } return Args.MakeArgString(Res + ".d"); } void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; // Determine the original source input. const Action *SourceAction = &JA; while (SourceAction->getKind() != Action::InputClass) { assert(!SourceAction->getInputs().empty() && "unexpected root action!"); SourceAction = SourceAction->getInputs()[0]; } // If -fno_integrated_as is used add -Q to the darwin assember driver to make // sure it runs its system assembler not clang's integrated assembler. // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as. // FIXME: at run-time detect assembler capabilities or rely on version // information forwarded by -target-assembler-version (future) if (Args.hasArg(options::OPT_fno_integrated_as)) { const llvm::Triple &T(getToolChain().getTriple()); if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) CmdArgs.push_back("-Q"); } // Forward -g, assuming we are dealing with an actual assembly file. if (SourceAction->getType() == types::TY_Asm || SourceAction->getType() == types::TY_PP_Asm) { if (Args.hasArg(options::OPT_gstabs)) CmdArgs.push_back("--gstabs"); else if (Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("-g"); } // Derived from asm spec. AddMachOArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. if (getToolChain().getArch() == llvm::Triple::x86 || getToolChain().getArch() == llvm::Triple::x86_64 || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); if (getToolChain().getArch() != llvm::Triple::x86_64 && (((Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) && getMachOToolChain().isKernelStatic()) || Args.hasArg(options::OPT_static))) CmdArgs.push_back("-static"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Input.isFilename() && "Invalid input."); CmdArgs.push_back(Input.getFilename()); // asm_final spec is empty. const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void darwin::MachOTool::anchor() {} void darwin::MachOTool::AddMachOArch(const ArgList &Args, ArgStringList &CmdArgs) const { StringRef ArchName = getMachOToolChain().getMachOArchName(Args); // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); CmdArgs.push_back(Args.MakeArgString(ArchName)); // FIXME: Is this needed anymore? if (ArchName == "arm") CmdArgs.push_back("-force_cpusubtype_ALL"); } bool darwin::Link::NeedsTempPath(const InputInfoList &Inputs) const { // We only need to generate a temp path for LTO if we aren't compiling object // files. When compiling source files, we run 'dsymutil' after linking. We // don't run 'dsymutil' when compiling object files. for (const auto &Input : Inputs) if (Input.getType() != types::TY_Object) return true; return false; } void darwin::Link::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs) const { const Driver &D = getToolChain().getDriver(); const toolchains::MachO &MachOTC = getMachOToolChain(); unsigned Version[3] = { 0, 0, 0 }; if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { bool HadExtra; if (!Driver::GetReleaseVersion(A->getValue(), Version[0], Version[1], Version[2], HadExtra) || HadExtra) D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); } // Newer linkers support -demangle. Pass it if supported and not disabled by // the user. if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("-demangle"); if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) CmdArgs.push_back("-export_dynamic"); // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) { const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); CmdArgs.push_back("-object_path_lto"); CmdArgs.push_back(TmpPath); } // Derived from the "link" spec. Args.AddAllArgs(CmdArgs, options::OPT_static); if (!Args.hasArg(options::OPT_static)) CmdArgs.push_back("-dynamic"); if (Args.hasArg(options::OPT_fgnu_runtime)) { // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu // here. How do we wish to handle such things? } if (!Args.hasArg(options::OPT_dynamiclib)) { AddMachOArch(Args, CmdArgs); // FIXME: Why do this only on this path? Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); Args.AddLastArg(CmdArgs, options::OPT_bundle); Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); Args.AddAllArgs(CmdArgs, options::OPT_client__name); Arg *A; if ((A = Args.getLastArg(options::OPT_compatibility__version)) || (A = Args.getLastArg(options::OPT_current__version)) || (A = Args.getLastArg(options::OPT_install__name))) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); Args.AddLastArg(CmdArgs, options::OPT_private__bundle); } else { CmdArgs.push_back("-dylib"); Arg *A; if ((A = Args.getLastArg(options::OPT_bundle)) || (A = Args.getLastArg(options::OPT_bundle__loader)) || (A = Args.getLastArg(options::OPT_client__name)) || (A = Args.getLastArg(options::OPT_force__flat__namespace)) || (A = Args.getLastArg(options::OPT_keep__private__externs)) || (A = Args.getLastArg(options::OPT_private__bundle))) D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) << "-dynamiclib"; Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, "-dylib_compatibility_version"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, "-dylib_current_version"); AddMachOArch(Args, CmdArgs); Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, "-dylib_install_name"); } Args.AddLastArg(CmdArgs, options::OPT_all__load); Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); if (MachOTC.isTargetIOSBased()) Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); Args.AddLastArg(CmdArgs, options::OPT_dead__strip); Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); Args.AddLastArg(CmdArgs, options::OPT_dynamic); Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list); Args.AddLastArg(CmdArgs, options::OPT_flat__namespace); Args.AddAllArgs(CmdArgs, options::OPT_force__load); Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names); Args.AddAllArgs(CmdArgs, options::OPT_image__base); Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. MachOTC.addMinVersionArgs(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); Args.AddLastArg(CmdArgs, options::OPT_single__module); Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined); Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused); if (const Arg *A = Args.getLastArg(options::OPT_fpie, options::OPT_fPIE, options::OPT_fno_pie, options::OPT_fno_PIE)) { if (A->getOption().matches(options::OPT_fpie) || A->getOption().matches(options::OPT_fPIE)) CmdArgs.push_back("-pie"); else CmdArgs.push_back("-no_pie"); } Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules); Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs); Args.AddAllArgs(CmdArgs, options::OPT_sectcreate); Args.AddAllArgs(CmdArgs, options::OPT_sectorder); Args.AddAllArgs(CmdArgs, options::OPT_seg1addr); Args.AddAllArgs(CmdArgs, options::OPT_segprot); Args.AddAllArgs(CmdArgs, options::OPT_segaddr); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr); Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table); Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); Args.AddAllArgs(CmdArgs, options::OPT_sub__library); Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); // Give --sysroot= preference, over the Apple specific behavior to also use // --isysroot as the syslibroot. StringRef sysroot = C.getSysRoot(); if (sysroot != "") { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); CmdArgs.push_back(A->getValue()); } Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); Args.AddAllArgs(CmdArgs, options::OPT_umbrella); Args.AddAllArgs(CmdArgs, options::OPT_undefined); Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); Args.AddLastArg(CmdArgs, options::OPT_X_Flag); Args.AddAllArgs(CmdArgs, options::OPT_y); Args.AddLastArg(CmdArgs, options::OPT_w); Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size); Args.AddAllArgs(CmdArgs, options::OPT_segs__read__); Args.AddLastArg(CmdArgs, options::OPT_seglinkedit); Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit); Args.AddAllArgs(CmdArgs, options::OPT_sectalign); Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols); Args.AddAllArgs(CmdArgs, options::OPT_segcreate); Args.AddLastArg(CmdArgs, options::OPT_whyload); Args.AddLastArg(CmdArgs, options::OPT_whatsloaded); Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); Args.AddLastArg(CmdArgs, options::OPT_dylinker); Args.AddLastArg(CmdArgs, options::OPT_Mach); } enum LibOpenMP { LibUnknown, LibGOMP, LibIOMP5 }; void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { assert(Output.getType() == types::TY_Image && "Invalid linker output type."); // If the number of arguments surpasses the system limits, we will encode the // input files in a separate file, shortening the command line. To this end, // build a list of input file names that can be passed via a file with the // -filelist linker option. llvm::opt::ArgStringList InputFileList; // The logic here is derived from gcc's behavior; most of which // comes from specs (starting with link_command). Consult gcc for // more information. ArgStringList CmdArgs; /// Hack(tm) to ignore linking errors when we are doing ARC migration. if (Args.hasArg(options::OPT_ccc_arcmt_check, options::OPT_ccc_arcmt_migrate)) { for (const auto &Arg : Args) Arg->claim(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("touch")); CmdArgs.push_back(Output.getFilename()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); return; } // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); Args.AddAllArgs(CmdArgs, options::OPT_d_Flag); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_u_Group); Args.AddLastArg(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_r); // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading // members of static archive libraries which implement Objective-C classes or // categories. if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) CmdArgs.push_back("-ObjC"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_L); LibOpenMP UsedOpenMPLib = LibUnknown; if (Args.hasArg(options::OPT_fopenmp)) { UsedOpenMPLib = LibGOMP; } else if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) { UsedOpenMPLib = llvm::StringSwitch(A->getValue()) .Case("libgomp", LibGOMP) .Case("libiomp5", LibIOMP5) .Default(LibUnknown); if (UsedOpenMPLib == LibUnknown) getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << A->getValue(); } switch (UsedOpenMPLib) { case LibGOMP: CmdArgs.push_back("-lgomp"); break; case LibIOMP5: CmdArgs.push_back("-liomp5"); break; case LibUnknown: break; } AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); // Build the input file for -filelist (list of linker input files) in case we // need it later for (const auto &II : Inputs) { if (!II.isFilename()) { // This is a linker input argument. // We cannot mix input arguments and file names in a -filelist input, thus // we prematurely stop our list (remaining files shall be passed as // arguments). if (InputFileList.size() > 0) break; continue; } InputFileList.push_back(II.getFilename()); } if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { // We use arclite library for both ARC and subscripting support. getMachOToolChain().AddLinkARCArgs(Args, CmdArgs); CmdArgs.push_back("-framework"); CmdArgs.push_back("Foundation"); // Link libobj. CmdArgs.push_back("-lobjc"); } if (LinkingOutput) { CmdArgs.push_back("-arch_multiple"); CmdArgs.push_back("-final_output"); CmdArgs.push_back(LinkingOutput); } if (Args.hasArg(options::OPT_fnested_functions)) CmdArgs.push_back("-allow_stack_execute"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); // link_ssp spec is empty. // Let the tool chain choose which runtime library to link. getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { // endfile_spec is empty. } Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_F); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); std::unique_ptr Cmd = llvm::make_unique(JA, *this, Exec, CmdArgs); Cmd->setInputFileList(std::move(InputFileList)); C.addCommand(std::move(Cmd)); } void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("-create"); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-output"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) { assert(II.isFilename() && "Unexpected lipo input."); CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); const InputInfo &Input = Inputs[0]; assert(Input.isFilename() && "Unexpected dsymutil input."); CmdArgs.push_back(Input.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("--verify"); CmdArgs.push_back("--debug-info"); CmdArgs.push_back("--eh-frame"); CmdArgs.push_back("--quiet"); assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); const InputInfo &Input = Inputs[0]; assert(Input.isFilename() && "Unexpected verify input"); // Grabbing the output of the earlier dsymutil run. CmdArgs.push_back(Input.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void solaris::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { // FIXME: Find a real GCC, don't hard-code versions here std::string GCCLibPath = "/usr/gcc/4.5/lib/gcc/"; const llvm::Triple &T = getToolChain().getTriple(); std::string LibPath = "/usr/lib/"; llvm::Triple::ArchType Arch = T.getArch(); switch (Arch) { case llvm::Triple::x86: GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str() + "/4.5.2/"; break; case llvm::Triple::x86_64: GCCLibPath += ("i386-" + T.getVendorName() + "-" + T.getOSName()).str(); GCCLibPath += "/4.5.2/amd64/"; LibPath += "amd64/"; break; default: llvm_unreachable("Unsupported architecture"); } ArgStringList CmdArgs; // Demangle C++ names in errors CmdArgs.push_back("-C"); if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); CmdArgs.push_back("-dn"); } else { CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("--dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(LibPath + "ld.so.1")); } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString(LibPath + "crt1.o")); CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o")); CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o")); CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o")); } else { CmdArgs.push_back(Args.MakeArgString(LibPath + "crti.o")); CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o")); CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o")); } if (getToolChain().getDriver().CCCIsCXX()) CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o")); } CmdArgs.push_back(Args.MakeArgString("-L" + GCCLibPath)); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (getToolChain().getDriver().CCCIsCXX()) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lgcc_s"); if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtend.o")); } CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o")); addProfileRT(getToolChain(), Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; bool NeedsKPIC = false; switch (getToolChain().getArch()) { case llvm::Triple::x86: // When building 32-bit code on OpenBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. CmdArgs.push_back("--32"); break; case llvm::Triple::ppc: CmdArgs.push_back("-mppc"); CmdArgs.push_back("-many"); break; case llvm::Triple::sparc: CmdArgs.push_back("-32"); NeedsKPIC = true; break; case llvm::Triple::sparcv9: CmdArgs.push_back("-64"); CmdArgs.push_back("-Av9a"); NeedsKPIC = true; break; case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-mabi"); CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else CmdArgs.push_back("-EL"); NeedsKPIC = true; break; } default: break; } if (NeedsKPIC) addAssemblerKPIC(Args, CmdArgs); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else if (getToolChain().getArch() == llvm::Triple::mips64el) CmdArgs.push_back("-EL"); if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } if (Args.hasArg(options::OPT_nopie)) CmdArgs.push_back("-nopie"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("gcrt0.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } std::string Triple = getToolChain().getTripleString(); if (Triple.substr(0, 6) == "x86_64") Triple.replace(0, 6, "amd64"); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) { if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtendS.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("gcrt0.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) { if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); } StringRef MyArch; switch (getToolChain().getTriple().getArch()) { case llvm::Triple::arm: MyArch = "arm"; break; case llvm::Triple::x86: MyArch = "i386"; break; case llvm::Triple::x86_64: MyArch = "amd64"; break; default: llvm_unreachable("Unsupported architecture"); } CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch)); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtendS.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. if (getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); else if (getToolChain().getArch() == llvm::Triple::ppc) CmdArgs.push_back("-a32"); else if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mipsel || getToolChain().getArch() == llvm::Triple::mips64 || getToolChain().getArch() == llvm::Triple::mips64el) { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else CmdArgs.push_back("-EL"); addAssemblerKPIC(Args, CmdArgs); } else if (getToolChain().getArch() == llvm::Triple::arm || getToolChain().getArch() == llvm::Triple::armeb || getToolChain().getArch() == llvm::Triple::thumb || getToolChain().getArch() == llvm::Triple::thumbeb) { const Driver &D = getToolChain().getDriver(); const llvm::Triple &Triple = getToolChain().getTriple(); StringRef FloatABI = arm::getARMFloatABI(D, Args, Triple); if (FloatABI == "hard") { CmdArgs.push_back("-mfpu=vfp"); } else { CmdArgs.push_back("-mfpu=softvfp"); } switch(getToolChain().getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: CmdArgs.push_back("-meabi=5"); break; default: CmdArgs.push_back("-matpcs"); } } else if (getToolChain().getArch() == llvm::Triple::sparc || getToolChain().getArch() == llvm::Triple::sparcv9) { if (getToolChain().getArch() == llvm::Triple::sparc) CmdArgs.push_back("-Av8plusa"); else CmdArgs.push_back("-Av9a"); addAssemblerKPIC(Args, CmdArgs); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::FreeBSD& ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (IsPIE) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } if (ToolChain.getTriple().getOSMajorVersion() >= 9) { llvm::Triple::ArchType Arch = ToolChain.getArch(); if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { CmdArgs.push_back("--hash-style=both"); } } CmdArgs.push_back("--enable-new-dtags"); } // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct ld in the base system to link 32-bit code. if (ToolChain.getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386_fbsd"); } if (ToolChain.getArch() == llvm::Triple::ppc) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_fbsd"); } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const char *crtbegin = nullptr; if (Args.hasArg(options::OPT_static)) crtbegin = "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared) || IsPIE) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); const ToolChain::path_list &Paths = ToolChain.getFilePaths(); for (const auto &Path : Paths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgcc_p"); else CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } if (Args.hasArg(options::OPT_pthread)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (Args.hasArg(options::OPT_pg)) { if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); else CmdArgs.push_back("-lc_p"); CmdArgs.push_back("-lgcc_p"); } else { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } addProfileRT(ToolChain, Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; // GNU as needs different flags for creating the correct output format // on architectures with different ABIs or optional feature sets. switch (getToolChain().getArch()) { case llvm::Triple::x86: CmdArgs.push_back("--32"); break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { std::string MArch(arm::getARMTargetCPU(Args, getToolChain().getTriple())); CmdArgs.push_back(Args.MakeArgString("-mcpu=" + MArch)); break; } case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data()); if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else CmdArgs.push_back("-EL"); addAssemblerKPIC(Args, CmdArgs); break; } case llvm::Triple::sparc: CmdArgs.push_back("-32"); addAssemblerKPIC(Args, CmdArgs); break; case llvm::Triple::sparcv9: CmdArgs.push_back("-64"); CmdArgs.push_back("-Av9"); addAssemblerKPIC(Args, CmdArgs); break; default: break; } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld.elf_so"); } } // Many NetBSD architectures support more than one ABI. // Determine the correct emulation for ld. switch (getToolChain().getArch()) { case llvm::Triple::x86: CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); break; case llvm::Triple::arm: case llvm::Triple::thumb: CmdArgs.push_back("-m"); switch (getToolChain().getTriple().getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelf_nbsd_eabi"); break; case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: CmdArgs.push_back("armelf_nbsd_eabihf"); break; default: CmdArgs.push_back("armelf_nbsd"); break; } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getTriple()); CmdArgs.push_back("-m"); switch (getToolChain().getTriple().getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelfb_nbsd_eabi"); break; case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: CmdArgs.push_back("armelfb_nbsd_eabihf"); break; default: CmdArgs.push_back("armelfb_nbsd"); break; } break; case llvm::Triple::mips64: case llvm::Triple::mips64el: if (mips::hasMipsAbiArg(Args, "32")) { CmdArgs.push_back("-m"); if (getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("elf32btsmip"); else CmdArgs.push_back("elf32ltsmip"); } else if (mips::hasMipsAbiArg(Args, "64")) { CmdArgs.push_back("-m"); if (getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("elf64btsmip"); else CmdArgs.push_back("elf64ltsmip"); } break; case llvm::Triple::ppc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_nbsd"); break; case llvm::Triple::ppc64: case llvm::Triple::ppc64le: CmdArgs.push_back("-m"); CmdArgs.push_back("elf64ppc"); break; case llvm::Triple::sparc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32_sparc"); break; case llvm::Triple::sparcv9: CmdArgs.push_back("-m"); CmdArgs.push_back("elf64_sparc"); break; default: break; } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); unsigned Major, Minor, Micro; getToolChain().getTriple().getOSVersion(Major, Minor, Micro); bool useLibgcc = true; if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) { switch(getToolChain().getArch()) { case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: case llvm::Triple::x86: case llvm::Triple::x86_64: useLibgcc = false; break; default: break; } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); if (useLibgcc) { if (Args.hasArg(options::OPT_static)) { // libgcc_eh depends on libc, so resolve as much as possible, // pull in any new requirements from libc and then get the rest // of libgcc. CmdArgs.push_back("-lgcc_eh"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } else { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtend.o"))); else CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtendS.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( "crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; bool NeedsKPIC = false; // Add --32/--64 to make sure we get the format we want. // This is incomplete if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("--32"); } else if (getToolChain().getArch() == llvm::Triple::x86_64) { if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) CmdArgs.push_back("--x32"); else CmdArgs.push_back("--64"); } else if (getToolChain().getArch() == llvm::Triple::ppc) { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back("-many"); } else if (getToolChain().getArch() == llvm::Triple::ppc64) { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-many"); } else if (getToolChain().getArch() == llvm::Triple::ppc64le) { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-many"); CmdArgs.push_back("-mlittle-endian"); } else if (getToolChain().getArch() == llvm::Triple::sparc) { CmdArgs.push_back("-32"); CmdArgs.push_back("-Av8plusa"); NeedsKPIC = true; } else if (getToolChain().getArch() == llvm::Triple::sparcv9) { CmdArgs.push_back("-64"); CmdArgs.push_back("-Av9a"); NeedsKPIC = true; } else if (getToolChain().getArch() == llvm::Triple::arm || getToolChain().getArch() == llvm::Triple::armeb) { StringRef MArch = getToolChain().getArchName(); if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") CmdArgs.push_back("-mfpu=neon"); if (MArch == "armv8" || MArch == "armv8a" || MArch == "armv8-a" || MArch == "armebv8" || MArch == "armebv8a" || MArch == "armebv8-a") CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); StringRef ARMFloatABI = tools::arm::getARMFloatABI( getToolChain().getDriver(), Args, getToolChain().getTriple()); CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=" + ARMFloatABI)); Args.AddLastArg(CmdArgs, options::OPT_march_EQ); // FIXME: remove krait check when GNU tools support krait cpu // for now replace it with -march=armv7-a to avoid a lower // march from being picked in the absence of a cpu flag. Arg *A; if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && StringRef(A->getValue()) == "krait") CmdArgs.push_back("-march=armv7-a"); else Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); } else if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mipsel || getToolChain().getArch() == llvm::Triple::mips64 || getToolChain().getArch() == llvm::Triple::mips64el) { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); ABIName = getGnuCompatibleMipsABIName(ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, // or -mshared (not implemented) is in effect. bool IsPicOrPie = false; if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, options::OPT_fpie, options::OPT_fno_pie)) { if (A->getOption().matches(options::OPT_fPIC) || A->getOption().matches(options::OPT_fpic) || A->getOption().matches(options::OPT_fPIE) || A->getOption().matches(options::OPT_fpie)) IsPicOrPie = true; } if (!IsPicOrPie) CmdArgs.push_back("-mno-shared"); // LLVM doesn't support -mplt yet and acts as if it is always given. // However, -mplt has no effect with the N64 ABI. CmdArgs.push_back(ABIName == "64" ? "-KPIC" : "-call_nonpic"); if (getToolChain().getArch() == llvm::Triple::mips || getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else CmdArgs.push_back("-EL"); if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { if (StringRef(A->getValue()) == "2008") CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); } // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, options::OPT_mfp64)) { A->claim(); A->render(Args, CmdArgs); } else if (mips::isFPXXDefault(getToolChain().getTriple(), CPUName, ABIName)) CmdArgs.push_back("-mfpxx"); // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of // -mno-mips16 is actually -no-mips16. if (Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { if (A->getOption().matches(options::OPT_mips16)) { A->claim(); A->render(Args, CmdArgs); } else { A->claim(); CmdArgs.push_back("-no-mips16"); } } Args.AddLastArg(CmdArgs, options::OPT_mmicromips, options::OPT_mno_micromips); Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { // Do not use AddLastArg because not all versions of MIPS assembler // support -mmsa / -mno-msa options. if (A->getOption().matches(options::OPT_mmsa)) CmdArgs.push_back(Args.MakeArgString("-mmsa")); } Args.AddLastArg(CmdArgs, options::OPT_mhard_float, options::OPT_msoft_float); Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, options::OPT_mno_odd_spreg); NeedsKPIC = true; } else if (getToolChain().getArch() == llvm::Triple::systemz) { // Always pass an -march option, since our default of z10 is later // than the GNU assembler's default. StringRef CPUName = getSystemZTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); } if (NeedsKPIC) addAssemblerKPIC(Args, CmdArgs); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); // Handle the debug info splitting at object creation time if we're // creating an object. // TODO: Currently only works on linux with newer objcopy. if (Args.hasArg(options::OPT_gsplit_dwarf) && getToolChain().getTriple().isOSLinux()) SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDebugName(Args, Inputs)); } static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android; bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || Args.hasArg(options::OPT_static); if (!D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); if (StaticLibgcc || isAndroid) { if (D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); } else { if (!D.CCCIsCXX()) CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); if (!D.CCCIsCXX()) CmdArgs.push_back("--no-as-needed"); } if (StaticLibgcc && !isAndroid) CmdArgs.push_back("-lgcc_eh"); else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX()) CmdArgs.push_back("-lgcc"); // According to Android ABI, we have to link with libdl if we are // linking with non-static libgcc. // // NOTE: This fixes a link error on Android MIPS as well. The non-static // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl. if (isAndroid && !StaticLibgcc) CmdArgs.push_back("-ldl"); } static std::string getLinuxDynamicLinker(const ArgList &Args, const toolchains::Linux &ToolChain) { if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) { if (ToolChain.getTriple().isArch64Bit()) return "/system/bin/linker64"; else return "/system/bin/linker"; } else if (ToolChain.getArch() == llvm::Triple::x86 || ToolChain.getArch() == llvm::Triple::sparc) return "/lib/ld-linux.so.2"; else if (ToolChain.getArch() == llvm::Triple::aarch64) return "/lib/ld-linux-aarch64.so.1"; else if (ToolChain.getArch() == llvm::Triple::aarch64_be) return "/lib/ld-linux-aarch64_be.so.1"; else if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::thumb) { if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) return "/lib/ld-linux-armhf.so.3"; else return "/lib/ld-linux.so.3"; } else if (ToolChain.getArch() == llvm::Triple::armeb || ToolChain.getArch() == llvm::Triple::thumbeb) { if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) return "/lib/ld-linux-armhf.so.3"; /* TODO: check which dynamic linker name. */ else return "/lib/ld-linux.so.3"; /* TODO: check which dynamic linker name. */ } else if (ToolChain.getArch() == llvm::Triple::mips || ToolChain.getArch() == llvm::Triple::mipsel || ToolChain.getArch() == llvm::Triple::mips64 || ToolChain.getArch() == llvm::Triple::mips64el) { StringRef CPUName; StringRef ABIName; mips::getMipsCPUAndABI(Args, ToolChain.getTriple(), CPUName, ABIName); bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple()); StringRef LibDir = llvm::StringSwitch(ABIName) .Case("o32", "/lib") .Case("n32", "/lib32") .Case("n64", "/lib64") .Default("/lib"); StringRef LibName; if (mips::isUCLibc(Args)) LibName = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0"; else LibName = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1"; return (LibDir + "/" + LibName).str(); } else if (ToolChain.getArch() == llvm::Triple::ppc) return "/lib/ld.so.1"; else if (ToolChain.getArch() == llvm::Triple::ppc64) { if (ppc::hasPPCAbiArg(Args, "elfv2")) return "/lib64/ld64.so.2"; return "/lib64/ld64.so.1"; } else if (ToolChain.getArch() == llvm::Triple::ppc64le) { if (ppc::hasPPCAbiArg(Args, "elfv1")) return "/lib64/ld64.so.1"; return "/lib64/ld64.so.2"; } else if (ToolChain.getArch() == llvm::Triple::systemz) return "/lib64/ld64.so.1"; else if (ToolChain.getArch() == llvm::Triple::sparcv9) return "/lib64/ld-linux.so.2"; else if (ToolChain.getArch() == llvm::Triple::x86_64 && ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32) return "/libx32/ld-linux-x32.so.2"; else return "/lib64/ld-linux-x86-64.so.2"; } static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { // Make use of compiler-rt if --rtlib option is used ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); switch (RLT) { case ToolChain::RLT_CompilerRT: switch (TC.getTriple().getOS()) { default: llvm_unreachable("unsupported OS"); case llvm::Triple::Win32: case llvm::Triple::Linux: addClangRT(TC, Args, CmdArgs); break; } break; case ToolChain::RLT_Libgcc: AddLibgcc(TC.getTriple(), D, CmdArgs, Args); break; } } static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { switch (T.getArch()) { case llvm::Triple::x86: return "elf_i386"; case llvm::Triple::aarch64: return "aarch64linux"; case llvm::Triple::aarch64_be: return "aarch64_be_linux"; case llvm::Triple::arm: case llvm::Triple::thumb: return "armelf_linux_eabi"; case llvm::Triple::armeb: case llvm::Triple::thumbeb: return "armebelf_linux_eabi"; /* TODO: check which NAME. */ case llvm::Triple::ppc: return "elf32ppclinux"; case llvm::Triple::ppc64: return "elf64ppc"; case llvm::Triple::ppc64le: return "elf64lppc"; case llvm::Triple::sparc: return "elf32_sparc"; case llvm::Triple::sparcv9: return "elf64_sparc"; case llvm::Triple::mips: return "elf32btsmip"; case llvm::Triple::mipsel: return "elf32ltsmip"; case llvm::Triple::mips64: if (mips::hasMipsAbiArg(Args, "n32")) return "elf32btsmipn32"; return "elf64btsmip"; case llvm::Triple::mips64el: if (mips::hasMipsAbiArg(Args, "n32")) return "elf32ltsmipn32"; return "elf64ltsmip"; case llvm::Triple::systemz: return "elf64_s390"; case llvm::Triple::x86_64: if (T.getEnvironment() == llvm::Triple::GNUX32) return "elf32_x86_64"; return "elf_x86_64"; default: llvm_unreachable("Unexpected arch"); } } void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::Linux& ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); const bool isAndroid = ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; const bool IsPIE = !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault() || // On Android every code is PIC so every executable is PIE // Cannot use isPIEDefault here since otherwise // PIE only logic will be enabled during compilation isAndroid); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (IsPIE) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); if (ToolChain.getArch() == llvm::Triple::armeb || ToolChain.getArch() == llvm::Triple::thumbeb) arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getTriple()); for (const auto &Opt : ToolChain.ExtraOpts) CmdArgs.push_back(Opt.c_str()); if (!Args.hasArg(options::OPT_static)) { CmdArgs.push_back("--eh-frame-hdr"); } CmdArgs.push_back("-m"); CmdArgs.push_back(getLDMOption(ToolChain.getTriple(), Args)); if (Args.hasArg(options::OPT_static)) { if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::armeb || ToolChain.getArch() == llvm::Triple::thumb || ToolChain.getArch() == llvm::Triple::thumbeb) CmdArgs.push_back("-Bstatic"); else CmdArgs.push_back("-static"); } else if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } if (ToolChain.getArch() == llvm::Triple::arm || ToolChain.getArch() == llvm::Triple::armeb || ToolChain.getArch() == llvm::Triple::thumb || ToolChain.getArch() == llvm::Triple::thumbeb || (!Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString( D.DyldPrefix + getLinuxDynamicLinker(Args, ToolChain))); } CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!isAndroid) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)){ if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); } const char *crtbegin; if (Args.hasArg(options::OPT_static)) crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; else if (IsPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); // Add crtfastmath.o if available and fast math is enabled. ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); const ToolChain::path_list &Paths = ToolChain.getFilePaths(); for (const auto &Path : Paths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); if (D.IsUsingLTO(Args)) AddGoldPlugin(ToolChain, Args, CmdArgs); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); // The profile runtime also needs access to system libraries. addProfileRT(getToolChain(), Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bdynamic"); CmdArgs.push_back("-lm"); } if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--start-group"); if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); LibOpenMP UsedOpenMPLib = LibUnknown; if (Args.hasArg(options::OPT_fopenmp)) { UsedOpenMPLib = LibGOMP; } else if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) { UsedOpenMPLib = llvm::StringSwitch(A->getValue()) .Case("libgomp", LibGOMP) .Case("libiomp5", LibIOMP5) .Default(LibUnknown); if (UsedOpenMPLib == LibUnknown) D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << A->getValue(); } switch (UsedOpenMPLib) { case LibGOMP: CmdArgs.push_back("-lgomp"); // FIXME: Exclude this for platforms with libgomp that don't require // librt. Most modern Linux platforms require it, but some may not. CmdArgs.push_back("-lrt"); break; case LibIOMP5: CmdArgs.push_back("-liomp5"); break; case LibUnknown: break; } AddRunTimeLibs(ToolChain, D, CmdArgs, Args); if ((Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads) || UsedOpenMPLib != LibUnknown) && !isAndroid) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); else AddRunTimeLibs(ToolChain, D, CmdArgs, Args); } if (!Args.hasArg(options::OPT_nostartfiles)) { const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; else if (IsPIE) crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); if (!isAndroid) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } } C.addCommand( llvm::make_unique(JA, *this, ToolChain.Linker.c_str(), CmdArgs)); } void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); addProfileRT(getToolChain(), Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lCompilerRT-Generic"); CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } /// DragonFly Tools // For now, DragonFly Assemble does just about the same as for // FreeBSD, but this may change soon. void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct as in the base system to assemble 32-bit code. if (getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; bool UseGCC47 = llvm::sys::fs::exists("/usr/lib/gcc47"); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-Bshareable"); else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } CmdArgs.push_back("--hash-style=both"); } // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct ld in the base system to link 32-bit code. if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("gcrt1.o"))); else { if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("Scrt1.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crt1.o"))); } } CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crti.o"))); if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbeginS.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of // rpaths if (UseGCC47) CmdArgs.push_back("-L/usr/lib/gcc47"); else CmdArgs.push_back("-L/usr/lib/gcc44"); if (!Args.hasArg(options::OPT_static)) { if (UseGCC47) { CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib/gcc47"); } else { CmdArgs.push_back("-rpath"); CmdArgs.push_back("/usr/lib/gcc44"); } } if (D.CCCIsCXX()) { getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); if (!Args.hasArg(options::OPT_nolibc)) { CmdArgs.push_back("-lc"); } if (UseGCC47) { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_libgcc)) { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("-lgcc_eh"); } else { if (Args.hasArg(options::OPT_shared_libgcc)) { CmdArgs.push_back("-lgcc_pic"); if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lgcc"); } else { CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_pic"); CmdArgs.push_back("--no-as-needed"); } } } else { if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc_pic"); } else { CmdArgs.push_back("-lgcc"); } } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString( getToolChain().GetFilePath("crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } // Try to find Exe from a Visual Studio distribution. This first tries to find // an installed copy of Visual Studio and, failing that, looks in the PATH, // making sure that whatever executable that's found is not a same-named exe // from clang itself to prevent clang from falling back to itself. static std::string FindVisualStudioExecutable(const ToolChain &TC, const char *Exe, const char *ClangProgramPath) { const auto &MSVC = static_cast(TC); std::string visualStudioBinDir; if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath, visualStudioBinDir)) { SmallString<128> FilePath(visualStudioBinDir); llvm::sys::path::append(FilePath, Exe); if (llvm::sys::fs::can_execute(FilePath.c_str())) return FilePath.str(); } return Exe; } void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; const ToolChain &TC = getToolChain(); assert((Output.isFilename() || Output.isNothing()) && "invalid output"); if (Output.isFilename()) CmdArgs.push_back(Args.MakeArgString(std::string("-out:") + Output.getFilename())); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles) && !C.getDriver().IsCLMode()) CmdArgs.push_back("-defaultlib:libcmt"); if (!llvm::sys::Process::GetEnv("LIB")) { // If the VC environment hasn't been configured (perhaps because the user // did not run vcvarsall), try to build a consistent link environment. If // the environment variable is set however, assume the user knows what he's // doing. std::string VisualStudioDir; const auto &MSVC = static_cast(TC); if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) { SmallString<128> LibDir(VisualStudioDir); llvm::sys::path::append(LibDir, "VC", "lib"); switch (MSVC.getArch()) { case llvm::Triple::x86: // x86 just puts the libraries directly in lib break; case llvm::Triple::x86_64: llvm::sys::path::append(LibDir, "amd64"); break; case llvm::Triple::arm: llvm::sys::path::append(LibDir, "arm"); break; default: break; } CmdArgs.push_back( Args.MakeArgString(std::string("-libpath:") + LibDir.c_str())); } std::string WindowsSdkLibPath; if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath.c_str())); } CmdArgs.push_back("-nologo"); if (Args.hasArg(options::OPT_g_Group)) CmdArgs.push_back("-debug"); bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd); if (DLL) { CmdArgs.push_back(Args.MakeArgString("-dll")); SmallString<128> ImplibName(Output.getFilename()); llvm::sys::path::replace_extension(ImplibName, "lib"); CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName.str())); } if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); if (Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { static const char *CompilerRTComponents[] = { "asan_dynamic", "asan_dynamic_runtime_thunk", }; for (const auto &Component : CompilerRTComponents) CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component))); // Make sure the dynamic runtime thunk is not optimized out at link time // to ensure proper SEH handling. CmdArgs.push_back(Args.MakeArgString("-include:___asan_seh_interceptor")); } else if (DLL) { CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "asan_dll_thunk"))); } else { static const char *CompilerRTComponents[] = { "asan", "asan_cxx", }; for (const auto &Component : CompilerRTComponents) CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Component))); } } Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); // Add filenames, libraries, and other linker inputs. for (const auto &Input : Inputs) { if (Input.isFilename()) { CmdArgs.push_back(Input.getFilename()); continue; } const Arg &A = Input.getInputArg(); // Render -l options differently for the MSVC linker. if (A.getOption().matches(options::OPT_l)) { StringRef Lib = A.getValue(); const char *LinkLibArg; if (Lib.endswith(".lib")) LinkLibArg = Args.MakeArgString(Lib); else LinkLibArg = Args.MakeArgString(Lib + ".lib"); CmdArgs.push_back(LinkLibArg); continue; } // Otherwise, this is some other kind of linker input option like -Wl, -z, // or -L. Render it, even if MSVC doesn't understand it. A.renderAsInput(Args, CmdArgs); } // We need to special case some linker paths. In the case of lld, we need to // translate 'lld' into 'lld-link', and in the case of the regular msvc // linker, we need to use a special search algorithm. llvm::SmallString<128> linkPath; StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link"); if (Linker.equals_lower("lld")) Linker = "lld-link"; if (Linker.equals_lower("link")) { // If we're using the MSVC linker, it's not sufficient to just use link // from the program PATH, because other environments like GnuWin32 install // their own link.exe which may come first. linkPath = FindVisualStudioExecutable(TC, "link.exe", C.getDriver().getClangProgramPath()); } else { linkPath = Linker; llvm::sys::path::replace_extension(linkPath, "exe"); linkPath = TC.GetProgramPath(linkPath.c_str()); } const char *Exec = Args.MakeArgString(linkPath); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); } std::unique_ptr visualstudio::Compile::GetCommand( Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; CmdArgs.push_back("/nologo"); CmdArgs.push_back("/c"); // Compile only. CmdArgs.push_back("/W0"); // No warnings. // The goal is to be able to invoke this tool correctly based on // any flag accepted by clang-cl. // These are spelled the same way in clang and cl.exe,. Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U); Args.AddAllArgs(CmdArgs, options::OPT_I); // Optimization level. if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { if (A->getOption().getID() == options::OPT_O0) { CmdArgs.push_back("/Od"); } else { StringRef OptLevel = A->getValue(); if (OptLevel == "1" || OptLevel == "2" || OptLevel == "s") A->render(Args, CmdArgs); else if (OptLevel == "3") CmdArgs.push_back("/Ox"); } } // Flags for which clang-cl have an alias. // FIXME: How can we ensure this stays in sync with relevant clang-cl options? if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, /*default=*/false)) CmdArgs.push_back("/GR-"); if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections, options::OPT_fno_function_sections)) CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections ? "/Gy" : "/Gy-"); if (Arg *A = Args.getLastArg(options::OPT_fdata_sections, options::OPT_fno_data_sections)) CmdArgs.push_back( A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); if (Args.hasArg(options::OPT_fsyntax_only)) CmdArgs.push_back("/Zs"); if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only)) CmdArgs.push_back("/Z7"); std::vector Includes = Args.getAllArgValues(options::OPT_include); for (const auto &Include : Includes) CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include)); // Flags that can simply be passed through. Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); // The order of these flags is relevant, so pick the last one. if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) A->render(Args, CmdArgs); // Input filename. assert(Inputs.size() == 1); const InputInfo &II = Inputs[0]; assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); // Output filename. assert(Output.getType() == types::TY_Object); const char *Fo = Args.MakeArgString(std::string("/Fo") + Output.getFilename()); CmdArgs.push_back(Fo); const Driver &D = getToolChain().getDriver(); std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe", D.getClangProgramPath()); return llvm::make_unique(JA, *this, Args.MakeArgString(Exec), CmdArgs); } /// XCore Tools // We pass assemble and link construction to the xcc tool. void XCore::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); CmdArgs.push_back("-c"); if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) if (!A->getOption().matches(options::OPT_g0)) CmdArgs.push_back("-g"); if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, false)) CmdArgs.push_back("-fverbose-asm"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void XCore::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-v"); if (exceptionSettings(Args, getToolChain().getTriple())) CmdArgs.push_back("-fexceptions"); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void CrossWindows::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { claimNoWarnArgs(Args); const auto &TC = static_cast(getToolChain()); ArgStringList CmdArgs; const char *Exec; switch (TC.getArch()) { default: llvm_unreachable("unsupported architecture"); case llvm::Triple::arm: case llvm::Triple::thumb: break; case llvm::Triple::x86: CmdArgs.push_back("--32"); break; case llvm::Triple::x86_64: CmdArgs.push_back("--64"); break; } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); for (const auto &Input : Inputs) CmdArgs.push_back(Input.getFilename()); const std::string Assembler = TC.GetProgramPath("as"); Exec = Args.MakeArgString(Assembler); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } void CrossWindows::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = static_cast(getToolChain()); const llvm::Triple &T = TC.getTriple(); const Driver &D = TC.getDriver(); SmallString<128> EntryPoint; ArgStringList CmdArgs; const char *Exec; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo" Args.ClaimAllArgs(options::OPT_w); // Other warning options are already handled somewhere else. if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); CmdArgs.push_back("-m"); switch (TC.getArch()) { default: llvm_unreachable("unsupported architecture"); case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); break; case llvm::Triple::x86: CmdArgs.push_back("i386pe"); EntryPoint.append("_"); break; case llvm::Triple::x86_64: CmdArgs.push_back("i386pep"); break; } if (Args.hasArg(options::OPT_shared)) { switch (T.getArch()) { default: llvm_unreachable("unsupported architecture"); case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::x86_64: EntryPoint.append("_DllMainCRTStartup"); break; case llvm::Triple::x86: EntryPoint.append("_DllMainCRTStartup@12"); break; } CmdArgs.push_back("-shared"); CmdArgs.push_back("-Bdynamic"); CmdArgs.push_back("--enable-auto-image-base"); CmdArgs.push_back("--entry"); CmdArgs.push_back(Args.MakeArgString(EntryPoint)); } else { EntryPoint.append("mainCRTStartup"); CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" : "-Bdynamic"); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { CmdArgs.push_back("--entry"); CmdArgs.push_back(Args.MakeArgString(EntryPoint)); } // FIXME: handle subsystem } // NOTE: deal with multiple definitions on Windows (e.g. COMDAT) CmdArgs.push_back("--allow-multiple-definition"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) { SmallString<261> ImpLib(Output.getFilename()); llvm::sys::path::replace_extension(ImpLib, ".lib"); CmdArgs.push_back("--out-implib"); CmdArgs.push_back(Args.MakeArgString(ImpLib)); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { const std::string CRTPath(D.SysRoot + "/usr/lib/"); const char *CRTBegin; CRTBegin = Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj"; CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin)); } Args.AddAllArgs(CmdArgs, options::OPT_L); const auto &Paths = TC.getFilePaths(); for (const auto &Path : Paths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + Path)); AddLinkerInputs(TC, Inputs, Args, CmdArgs); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (StaticCXX) CmdArgs.push_back("-Bstatic"); TC.AddCXXStdlibLibArgs(Args, CmdArgs); if (StaticCXX) CmdArgs.push_back("-Bdynamic"); } if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { // TODO handle /MT[d] /MD[d] CmdArgs.push_back("-lmsvcrt"); AddRunTimeLibs(TC, D, CmdArgs, Args); } } const std::string Linker = TC.GetProgramPath("ld"); Exec = Args.MakeArgString(Linker); C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs)); } Index: vendor/clang/dist/lib/Parse/ParseExprCXX.cpp =================================================================== --- vendor/clang/dist/lib/Parse/ParseExprCXX.cpp (revision 278753) +++ vendor/clang/dist/lib/Parse/ParseExprCXX.cpp (revision 278754) @@ -1,3110 +1,3115 @@ //===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Expression parsing implementation for C++. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "RAIIObjectsForParser.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; static int SelectDigraphErrorMessage(tok::TokenKind Kind) { switch (Kind) { // template name case tok::unknown: return 0; // casts case tok::kw_const_cast: return 1; case tok::kw_dynamic_cast: return 2; case tok::kw_reinterpret_cast: return 3; case tok::kw_static_cast: return 4; default: llvm_unreachable("Unknown type for digraph error message."); } } // Are the two tokens adjacent in the same source file? bool Parser::areTokensAdjacent(const Token &First, const Token &Second) { SourceManager &SM = PP.getSourceManager(); SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength()); return FirstEnd == SM.getSpellingLoc(Second.getLocation()); } // Suggest fixit for "<::" after a cast. static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) { // Pull '<:' and ':' off token stream. if (!AtDigraph) PP.Lex(DigraphToken); PP.Lex(ColonToken); SourceRange Range; Range.setBegin(DigraphToken.getLocation()); Range.setEnd(ColonToken.getLocation()); P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph) << SelectDigraphErrorMessage(Kind) << FixItHint::CreateReplacement(Range, "< ::"); // Update token information to reflect their change in token type. ColonToken.setKind(tok::coloncolon); ColonToken.setLocation(ColonToken.getLocation().getLocWithOffset(-1)); ColonToken.setLength(2); DigraphToken.setKind(tok::less); DigraphToken.setLength(1); // Push new tokens back to token stream. PP.EnterToken(ColonToken); if (!AtDigraph) PP.EnterToken(DigraphToken); } // Check for '<::' which should be '< ::' instead of '[:' when following // a template name. void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS) { if (!Next.is(tok::l_square) || Next.getLength() != 2) return; Token SecondToken = GetLookAheadToken(2); if (!SecondToken.is(tok::colon) || !areTokensAdjacent(Next, SecondToken)) return; TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization)) return; FixDigraph(*this, PP, Next, SecondToken, tok::unknown, /*AtDigraph*/false); } /// \brief Emits an error for a left parentheses after a double colon. /// /// When a '(' is found after a '::', emit an error. Attempt to fix the token /// stream by removing the '(', and the matching ')' if found. void Parser::CheckForLParenAfterColonColon() { if (!Tok.is(tok::l_paren)) return; Token LParen = Tok; Token NextTok = GetLookAheadToken(1); Token StarTok = NextTok; // Check for (identifier or (*identifier Token IdentifierTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : StarTok; if (IdentifierTok.isNot(tok::identifier)) return; // Eat the '('. ConsumeParen(); Token RParen; // Do we have a ')' ? NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1); if (NextTok.is(tok::r_paren)) { RParen = NextTok; // Eat the '*' if it is present. if (StarTok.is(tok::star)) ConsumeToken(); // Eat the identifier. ConsumeToken(); // Add the identifier token back. PP.EnterToken(IdentifierTok); // Add the '*' back if it was present. if (StarTok.is(tok::star)) PP.EnterToken(StarTok); // Eat the ')'. ConsumeParen(); } Diag(LParen.getLocation(), diag::err_paren_after_colon_colon) << FixItHint::CreateRemoval(LParen.getLocation()) << FixItHint::CreateRemoval(RParen.getLocation()); } /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which /// may be preceded by '::'). Note that this routine will not parse ::new or /// ::delete; it will just leave them in the token stream. /// /// '::'[opt] nested-name-specifier /// '::' /// /// nested-name-specifier: /// type-name '::' /// namespace-name '::' /// nested-name-specifier identifier '::' /// nested-name-specifier 'template'[opt] simple-template-id '::' /// /// /// \param SS the scope specifier that will be set to the parsed /// nested-name-specifier (or empty) /// /// \param ObjectType if this nested-name-specifier is being parsed following /// the "." or "->" of a member access expression, this parameter provides the /// type of the object whose members are being accessed. /// /// \param EnteringContext whether we will be entering into the context of /// the nested-name-specifier after parsing it. /// /// \param MayBePseudoDestructor When non-NULL, points to a flag that /// indicates whether this nested-name-specifier may be part of a /// pseudo-destructor name. In this case, the flag will be set false /// if we don't actually end up parsing a destructor name. Moreorover, /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. /// /// \param IsTypename If \c true, this nested-name-specifier is known to be /// part of a type name. This is used to improve error recovery. /// /// \param LastII When non-NULL, points to an IdentifierInfo* that will be /// filled in with the leading identifier in the last component of the /// nested-name-specifier, if any. /// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { assert(!LastII && "want last identifier but have already annotated scope"); Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); ConsumeToken(); return false; } if (Tok.is(tok::annot_template_id)) { // If the current token is an annotated template id, it may already have // a scope specifier. Restore it. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); SS = TemplateId->SS; } if (LastII) *LastII = nullptr; bool HasScopeSpecifier = false; if (Tok.is(tok::coloncolon)) { // ::new and ::delete aren't nested-name-specifiers. tok::TokenKind NextKind = NextToken().getKind(); if (NextKind == tok::kw_new || NextKind == tok::kw_delete) return false; if (NextKind == tok::l_brace) { // It is invalid to have :: {, consume the scope qualifier and pretend // like we never saw it. Diag(ConsumeToken(), diag::err_expected) << tok::identifier; } else { // '::' - Global scope qualifier. if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS)) return true; CheckForLParenAfterColonColon(); HasScopeSpecifier = true; } } if (Tok.is(tok::kw___super)) { SourceLocation SuperLoc = ConsumeToken(); if (!Tok.is(tok::coloncolon)) { Diag(Tok.getLocation(), diag::err_expected_coloncolon_after_super); return true; } return Actions.ActOnSuperScopeSpecifier(SuperLoc, ConsumeToken(), SS); } bool CheckForDestructor = false; if (MayBePseudoDestructor && *MayBePseudoDestructor) { CheckForDestructor = true; *MayBePseudoDestructor = false; } if (!HasScopeSpecifier && (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))) { DeclSpec DS(AttrFactory); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); SourceLocation CCLoc; if (!TryConsumeToken(tok::coloncolon, CCLoc)) { AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc); return false; } if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc)) SS.SetInvalid(SourceRange(DeclLoc, CCLoc)); HasScopeSpecifier = true; } while (true) { if (HasScopeSpecifier) { // C++ [basic.lookup.classref]p5: // If the qualified-id has the form // // ::class-name-or-namespace-name::... // // the class-name-or-namespace-name is looked up in global scope as a // class-name or namespace-name. // // To implement this, we clear out the object type as soon as we've // seen a leading '::' or part of a nested-name-specifier. ObjectType = ParsedType(); if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion // token will cause assertion in // Preprocessor::AnnotatePreviousCachedTokens. SS.setEndLoc(Tok.getLocation()); cutOffParsing(); return true; } } // nested-name-specifier: // nested-name-specifier 'template'[opt] simple-template-id '::' // Parse the optional 'template' keyword, then make sure we have // 'identifier <' after it. if (Tok.is(tok::kw_template)) { // If we don't have a scope specifier or an object type, this isn't a // nested-name-specifier, since they aren't allowed to start with // 'template'. if (!HasScopeSpecifier && !ObjectType) break; TentativeParsingAction TPA(*this); SourceLocation TemplateKWLoc = ConsumeToken(); UnqualifiedId TemplateName; if (Tok.is(tok::identifier)) { // Consume the identifier. TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); } else if (Tok.is(tok::kw_operator)) { // We don't need to actually parse the unqualified-id in this case, // because a simple-template-id cannot start with 'operator', but // go ahead and parse it anyway for consistency with the case where // we already annotated the template-id. if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, TemplateName)) { TPA.Commit(); break; } if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId && TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) << TemplateName.getSourceRange(); TPA.Commit(); break; } } else { TPA.Revert(); break; } // If the next token is not '<', we have a qualified-id that refers // to a template name, such as T::template apply, but is not a // template-id. if (Tok.isNot(tok::less)) { TPA.Revert(); break; } // Commit to parsing the template-id. TPA.Commit(); TemplateTy Template; if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template)) { if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, TemplateName, false)) return true; } else return true; continue; } if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) { // We have // // template-id '::' // // So we need to check whether the template-id is a simple-template-id of // the right kind (it should name a type or be dependent), and then // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { *MayBePseudoDestructor = true; return false; } if (LastII) *LastII = TemplateId->Name; // Consume the template-id token. ConsumeToken(); assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); HasScopeSpecifier = true; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, CCLoc, EnteringContext)) { SourceLocation StartLoc = SS.getBeginLoc().isValid()? SS.getBeginLoc() : TemplateId->TemplateNameLoc; SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } continue; } // The rest of the nested-name-specifier possibilities start with // tok::identifier. if (Tok.isNot(tok::identifier)) break; IdentifierInfo &II = *Tok.getIdentifierInfo(); // nested-name-specifier: // type-name '::' // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { if (Actions.IsInvalidUnlessNestedName(getCurScope(), SS, II, Tok.getLocation(), Next.getLocation(), ObjectType, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't // recover like this. PP.LookAhead(1).is(tok::identifier)) { Diag(Next, diag::err_unexpected_colon_in_nested_name_spec) << FixItHint::CreateReplacement(Next.getLocation(), "::"); // Recover as if the user wrote '::'. Next.setKind(tok::coloncolon); } } if (Next.is(tok::coloncolon) && GetLookAheadToken(2).is(tok::l_brace)) { // It is invalid to have :: {, consume the scope qualifier and pretend // like we never saw it. Token Identifier = Tok; // Stash away the identifier. ConsumeToken(); // Eat the identifier, current token is now '::'. Diag(PP.getLocForEndOfToken(ConsumeToken()), diag::err_expected) << tok::identifier; UnconsumeToken(Identifier); // Stick the identifier back. Next = NextToken(); // Point Next at the '{' token. } if (Next.is(tok::coloncolon)) { if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && !Actions.isNonTypeNestedNameSpecifier( getCurScope(), SS, Tok.getLocation(), II, ObjectType)) { *MayBePseudoDestructor = true; return false; } if (ColonIsSacred) { const Token &Next2 = GetLookAheadToken(2); if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) || Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) { Diag(Next2, diag::err_unexpected_token_in_nested_name_spec) << Next2.getName() << FixItHint::CreateReplacement(Next.getLocation(), ":"); Token ColonColon; PP.Lex(ColonColon); ColonColon.setKind(tok::colon); PP.EnterToken(ColonColon); break; } } if (LastII) *LastII = &II; // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. Token Identifier = Tok; SourceLocation IdLoc = ConsumeToken(); assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && "NextToken() not working properly!"); Token ColonColon = Tok; SourceLocation CCLoc = ConsumeToken(); CheckForLParenAfterColonColon(); bool IsCorrectedToColon = false; bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr; if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, ObjectType, EnteringContext, SS, false, CorrectionFlagPtr)) { // Identifier is not recognized as a nested name, but we can have // mistyped '::' instead of ':'. if (CorrectionFlagPtr && IsCorrectedToColon) { ColonColon.setKind(tok::colon); PP.EnterToken(Tok); PP.EnterToken(ColonColon); Tok = Identifier; break; } SS.SetInvalid(SourceRange(IdLoc, CCLoc)); } HasScopeSpecifier = true; continue; } CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization)) { // We have found a template name, so annotate this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) return true; continue; } if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs, where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. unsigned DiagID = diag::err_missing_dependent_template_keyword; if (getLangOpts().MicrosoftExt) DiagID = diag::warn_missing_dependent_template_keyword; Diag(Tok.getLocation(), DiagID) << II.getName() << FixItHint::CreateInsertion(Tok.getLocation(), "template "); if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, SourceLocation(), TemplateName, ObjectType, EnteringContext, Template)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) return true; } else return true; continue; } } // We don't have any tokens that form the beginning of a // nested-name-specifier, so we're done. break; } // Even if we didn't see any pieces of a nested-name-specifier, we // still check whether there is a tilde in this position, which // indicates a potential pseudo-destructor. if (CheckForDestructor && Tok.is(tok::tilde)) *MayBePseudoDestructor = true; return false; } ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand, Token &Replacement) { SourceLocation TemplateKWLoc; UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, /*ObjectType=*/ParsedType(), TemplateKWLoc, Name)) return ExprError(); // This is only the direct operand of an & operator if it is not // followed by a postfix-expression suffix. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; return Actions.ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, nullptr, /*IsInlineAsmIdentifier=*/false, &Replacement); } /// ParseCXXIdExpression - Handle id-expression. /// /// id-expression: /// unqualified-id /// qualified-id /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id /// '::' template-id /// /// NOTE: The standard specifies that, for qualified-id, the parser does not /// expect: /// /// '::' conversion-function-id /// '::' '~' class-name /// /// This may cause a slight inconsistency on diagnostics: /// /// class C {}; /// namespace A {} /// void f() { /// :: A :: ~ C(); // Some Sema error about using destructor with a /// // namespace. /// :: ~ C(); // Some Parser error like 'unexpected ~'. /// } /// /// We simplify the parser a bit and make it work like: /// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' unqualified-id /// /// That way Sema can handle and report similar errors for namespaces and the /// global scope. /// /// The isAddressOfOperand parameter indicates that this id-expression is a /// direct operand of the address-of operator. This is, besides member contexts, /// the only place where a qualified-id naming a non-static class member may /// appear. /// ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // qualified-id: // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id // '::' unqualified-id // CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); Token Replacement; ExprResult Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); if (Result.isUnset()) { // If the ExprResult is valid but null, then typo correction suggested a // keyword replacement that needs to be reparsed. UnconsumeToken(Replacement); Result = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); } assert(!Result.isUnset() && "Typo correction suggested a keyword replacement " "for a previous keyword suggestion"); return Result; } /// ParseLambdaExpression - Parse a C++11 lambda expression. /// /// lambda-expression: /// lambda-introducer lambda-declarator[opt] compound-statement /// /// lambda-introducer: /// '[' lambda-capture[opt] ']' /// /// lambda-capture: /// capture-default /// capture-list /// capture-default ',' capture-list /// /// capture-default: /// '&' /// '=' /// /// capture-list: /// capture /// capture-list ',' capture /// /// capture: /// simple-capture /// init-capture [C++1y] /// /// simple-capture: /// identifier /// '&' identifier /// 'this' /// /// init-capture: [C++1y] /// identifier initializer /// '&' identifier initializer /// /// lambda-declarator: /// '(' parameter-declaration-clause ')' attribute-specifier[opt] /// 'mutable'[opt] exception-specification[opt] /// trailing-return-type[opt] /// ExprResult Parser::ParseLambdaExpression() { // Parse lambda-introducer. LambdaIntroducer Intro; Optional DiagID = ParseLambdaIntroducer(Intro); if (DiagID) { Diag(Tok, DiagID.getValue()); SkipUntil(tok::r_square, StopAtSemi); SkipUntil(tok::l_brace, StopAtSemi); SkipUntil(tok::r_brace, StopAtSemi); return ExprError(); } return ParseLambdaExpressionAfterIntroducer(Intro); } /// TryParseLambdaExpression - Use lookahead and potentially tentative /// parsing to determine if we are looking at a C++0x lambda expression, and parse /// it if we are. /// /// If we are not looking at a lambda expression, returns ExprError(). ExprResult Parser::TryParseLambdaExpression() { assert(getLangOpts().CPlusPlus11 && Tok.is(tok::l_square) && "Not at the start of a possible lambda expression."); const Token Next = NextToken(), After = GetLookAheadToken(2); // If lookahead indicates this is a lambda... if (Next.is(tok::r_square) || // [] Next.is(tok::equal) || // [= (Next.is(tok::amp) && // [&] or [&, (After.is(tok::r_square) || After.is(tok::comma))) || (Next.is(tok::identifier) && // [identifier] After.is(tok::r_square))) { return ParseLambdaExpression(); } // If lookahead indicates an ObjC message send... // [identifier identifier if (Next.is(tok::identifier) && After.is(tok::identifier)) { return ExprEmpty(); } // Here, we're stuck: lambda introducers and Objective-C message sends are // unambiguous, but it requires arbitrary lookhead. [a,b,c,d,e,f,g] is a // lambda, and [a,b,c,d,e,f,g h] is a Objective-C message send. Instead of // writing two routines to parse a lambda introducer, just try to parse // a lambda introducer first, and fall back if that fails. // (TryParseLambdaIntroducer never produces any diagnostic output.) LambdaIntroducer Intro; if (TryParseLambdaIntroducer(Intro)) return ExprEmpty(); return ParseLambdaExpressionAfterIntroducer(Intro); } /// \brief Parse a lambda introducer. /// \param Intro A LambdaIntroducer filled in with information about the /// contents of the lambda-introducer. /// \param SkippedInits If non-null, we are disambiguating between an Obj-C /// message send and a lambda expression. In this mode, we will /// sometimes skip the initializers for init-captures and not fully /// populate \p Intro. This flag will be set to \c true if we do so. /// \return A DiagnosticID if it hit something unexpected. The location for /// for the diagnostic is that of the current token. Optional Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, bool *SkippedInits) { typedef Optional DiagResult; assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['."); BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Intro.Range.setBegin(T.getOpenLocation()); bool first = true; // Parse capture-default. if (Tok.is(tok::amp) && (NextToken().is(tok::comma) || NextToken().is(tok::r_square))) { Intro.Default = LCD_ByRef; Intro.DefaultLoc = ConsumeToken(); first = false; } else if (Tok.is(tok::equal)) { Intro.Default = LCD_ByCopy; Intro.DefaultLoc = ConsumeToken(); first = false; } while (Tok.isNot(tok::r_square)) { if (!first) { if (Tok.isNot(tok::comma)) { // Provide a completion for a lambda introducer here. Except // in Objective-C, where this is Almost Surely meant to be a message // send. In that case, fail here and let the ObjC message // expression parser perform the completion. if (Tok.is(tok::code_completion) && !(getLangOpts().ObjC1 && Intro.Default == LCD_None && !Intro.Captures.empty())) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); cutOffParsing(); break; } return DiagResult(diag::err_expected_comma_or_rsquare); } ConsumeToken(); } if (Tok.is(tok::code_completion)) { // If we're in Objective-C++ and we have a bare '[', then this is more // likely to be a message receiver. if (getLangOpts().ObjC1 && first) Actions.CodeCompleteObjCMessageReceiver(getCurScope()); else Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/false); cutOffParsing(); break; } first = false; // Parse capture. LambdaCaptureKind Kind = LCK_ByCopy; SourceLocation Loc; IdentifierInfo *Id = nullptr; SourceLocation EllipsisLoc; ExprResult Init; if (Tok.is(tok::kw_this)) { Kind = LCK_This; Loc = ConsumeToken(); } else { if (Tok.is(tok::amp)) { Kind = LCK_ByRef; ConsumeToken(); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteLambdaIntroducer(getCurScope(), Intro, /*AfterAmpersand=*/true); cutOffParsing(); break; } } if (Tok.is(tok::identifier)) { Id = Tok.getIdentifierInfo(); Loc = ConsumeToken(); } else if (Tok.is(tok::kw_this)) { // FIXME: If we want to suggest a fixit here, will need to return more // than just DiagnosticID. Perhaps full DiagnosticBuilder that can be // Clear()ed to prevent emission in case of tentative parsing? return DiagResult(diag::err_this_captured_by_reference); } else { return DiagResult(diag::err_expected_capture); } if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); ExprVector Exprs; CommaLocsTy Commas; if (SkippedInits) { Parens.skipToEnd(); *SkippedInits = true; } else if (ParseExpressionList(Exprs, Commas)) { Parens.skipToEnd(); Init = ExprError(); } else { Parens.consumeClose(); Init = Actions.ActOnParenListExpr(Parens.getOpenLocation(), Parens.getCloseLocation(), Exprs); } } else if (Tok.is(tok::l_brace) || Tok.is(tok::equal)) { // Each lambda init-capture forms its own full expression, which clears // Actions.MaybeODRUseExprs. So create an expression evaluation context // to save the necessary state, and restore it later. EnterExpressionEvaluationContext EC(Actions, Sema::PotentiallyEvaluated); - TryConsumeToken(tok::equal); + bool HadEquals = TryConsumeToken(tok::equal); - if (!SkippedInits) + if (!SkippedInits) { + // Warn on constructs that will change meaning when we implement N3922 + if (!HadEquals && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_init_capture_direct_list_init) + << FixItHint::CreateInsertion(Tok.getLocation(), "="); + } Init = ParseInitializer(); - else if (Tok.is(tok::l_brace)) { + } else if (Tok.is(tok::l_brace)) { BalancedDelimiterTracker Braces(*this, tok::l_brace); Braces.consumeOpen(); Braces.skipToEnd(); *SkippedInits = true; } else { // We're disambiguating this: // // [..., x = expr // // We need to find the end of the following expression in order to // determine whether this is an Obj-C message send's receiver, a // C99 designator, or a lambda init-capture. // // Parse the expression to find where it ends, and annotate it back // onto the tokens. We would have parsed this expression the same way // in either case: both the RHS of an init-capture and the RHS of an // assignment expression are parsed as an initializer-clause, and in // neither case can anything be added to the scope between the '[' and // here. // // FIXME: This is horrible. Adding a mechanism to skip an expression // would be much cleaner. // FIXME: If there is a ',' before the next ']' or ':', we can skip to // that instead. (And if we see a ':' with no matching '?', we can // classify this as an Obj-C message send.) SourceLocation StartLoc = Tok.getLocation(); InMessageExpressionRAIIObject MaybeInMessageExpression(*this, true); Init = ParseInitializer(); if (Tok.getLocation() != StartLoc) { // Back out the lexing of the token after the initializer. PP.RevertCachedTokens(1); // Replace the consumed tokens with an appropriate annotation. Tok.setLocation(StartLoc); Tok.setKind(tok::annot_primary_expr); setExprAnnotation(Tok, Init); Tok.setAnnotationEndLoc(PP.getLastCachedTokenLocation()); PP.AnnotateCachedTokens(Tok); // Consume the annotated initializer. ConsumeToken(); } } } else TryConsumeToken(tok::ellipsis, EllipsisLoc); } // If this is an init capture, process the initialization expression // right away. For lambda init-captures such as the following: // const int x = 10; // auto L = [i = x+1](int a) { // return [j = x+2, // &k = x](char b) { }; // }; // keep in mind that each lambda init-capture has to have: // - its initialization expression executed in the context // of the enclosing/parent decl-context. // - but the variable itself has to be 'injected' into the // decl-context of its lambda's call-operator (which has // not yet been created). // Each init-expression is a full-expression that has to get // Sema-analyzed (for capturing etc.) before its lambda's // call-operator's decl-context, scope & scopeinfo are pushed on their // respective stacks. Thus if any variable is odr-used in the init-capture // it will correctly get captured in the enclosing lambda, if one exists. // The init-variables above are created later once the lambdascope and // call-operators decl-context is pushed onto its respective stack. // Since the lambda init-capture's initializer expression occurs in the // context of the enclosing function or lambda, therefore we can not wait // till a lambda scope has been pushed on before deciding whether the // variable needs to be captured. We also need to process all // lvalue-to-rvalue conversions and discarded-value conversions, // so that we can avoid capturing certain constant variables. // For e.g., // void test() { // const int x = 10; // auto L = [&z = x](char a) { <-- don't capture by the current lambda // return [y = x](int i) { <-- don't capture by enclosing lambda // return y; // } // }; // If x was not const, the second use would require 'L' to capture, and // that would be an error. ParsedType InitCaptureParsedType; if (Init.isUsable()) { // Get the pointer and store it in an lvalue, so we can use it as an // out argument. Expr *InitExpr = Init.get(); // This performs any lvalue-to-rvalue conversions if necessary, which // can affect what gets captured in the containing decl-context. QualType InitCaptureType = Actions.performLambdaInitCaptureInitialization( Loc, Kind == LCK_ByRef, Id, InitExpr); Init = InitExpr; InitCaptureParsedType.set(InitCaptureType); } Intro.addCapture(Kind, Loc, Id, EllipsisLoc, Init, InitCaptureParsedType); } T.consumeClose(); Intro.Range.setEnd(T.getCloseLocation()); return DiagResult(); } /// TryParseLambdaIntroducer - Tentatively parse a lambda introducer. /// /// Returns true if it hit something unexpected. bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { TentativeParsingAction PA(*this); bool SkippedInits = false; Optional DiagID(ParseLambdaIntroducer(Intro, &SkippedInits)); if (DiagID) { PA.Revert(); return true; } if (SkippedInits) { // Parse it again, but this time parse the init-captures too. PA.Revert(); Intro = LambdaIntroducer(); DiagID = ParseLambdaIntroducer(Intro); assert(!DiagID && "parsing lambda-introducer failed on reparse"); return false; } PA.Commit(); return false; } /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { SourceLocation LambdaBeginLoc = Intro.Range.getBegin(); Diag(LambdaBeginLoc, diag::warn_cxx98_compat_lambda); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); // FIXME: Call into Actions to add any init-capture declarations to the // scope while parsing the lambda-declarator and compound-statement. // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); Actions.PushLambdaScope(); TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); SourceLocation DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); SourceLocation LParenLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. ParsedAttributes Attr(AttrFactory); SmallVector ParamInfo; SourceLocation EllipsisLoc; if (Tok.isNot(tok::r_paren)) { Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); // For a generic lambda, each 'auto' within the parameter declaration // clause creates a template type parameter, so increment the depth. if (Actions.getCurGenericLambda()) ++CurTemplateDepthTracker; } T.consumeClose(); SourceLocation RParenLoc = T.getCloseLocation(); DeclEndLoc = RParenLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. MaybeParseGNUAttributes(Attr, &DeclEndLoc); // Parse 'mutable'[opt]. SourceLocation MutableLoc; if (TryConsumeToken(tok::kw_mutable, MutableLoc)) DeclEndLoc = MutableLoc; // Parse exception-specification[opt]. ExceptionSpecificationType ESpecType = EST_None; SourceRange ESpecRange; SmallVector DynamicExceptions; SmallVector DynamicExceptionRanges; ExprResult NoexceptExpr; CachedTokens *ExceptionSpecTokens; ESpecType = tryParseExceptionSpecification(/*Delayed=*/false, ESpecRange, DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); if (ESpecType != EST_None) DeclEndLoc = ESpecRange.getEnd(); // Parse attribute-specifier[opt]. MaybeParseCXX11Attributes(Attr, &DeclEndLoc); SourceLocation FunLocalRangeEnd = DeclEndLoc; // Parse trailing-return-type[opt]. if (Tok.is(tok::arrow)) { FunLocalRangeEnd = Tok.getLocation(); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } PrototypeScope.Exit(); SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, LParenLoc, ParamInfo.data(), ParamInfo.size(), EllipsisLoc, RParenLoc, DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, /*RefQualifierLoc=*/NoLoc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), DynamicExceptionRanges.data(), DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/nullptr, LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow) || Tok.is(tok::kw___attribute) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. unsigned TokKind = 0; switch (Tok.getKind()) { case tok::kw_mutable: TokKind = 0; break; case tok::arrow: TokKind = 1; break; case tok::kw___attribute: case tok::l_square: TokKind = 2; break; default: llvm_unreachable("Unknown token kind"); } Diag(Tok, diag::err_lambda_missing_parens) << TokKind << FixItHint::CreateInsertion(Tok.getLocation(), "() "); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation DeclEndLoc = DeclLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. ParsedAttributes Attr(AttrFactory); MaybeParseGNUAttributes(Attr, &DeclEndLoc); // Parse 'mutable', if it's there. SourceLocation MutableLoc; if (Tok.is(tok::kw_mutable)) { MutableLoc = ConsumeToken(); DeclEndLoc = MutableLoc; } // Parse attribute-specifier[opt]. MaybeParseCXX11Attributes(Attr, &DeclEndLoc); // Parse the return type, if there is one. if (Tok.is(tok::arrow)) { SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) DeclEndLoc = Range.getEnd(); } SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, /*isAmbiguous=*/false, /*LParenLoc=*/NoLoc, /*Params=*/nullptr, /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, /*TypeQuals=*/0, /*RefQualifierIsLValueRef=*/true, /*RefQualifierLoc=*/NoLoc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, MutableLoc, EST_None, /*ESpecLoc=*/NoLoc, /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); } // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope; ParseScope BodyScope(this, ScopeFlags); Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); // Parse compound-statement. if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lambda_body); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); } StmtResult Stmt(ParseCompoundStatementBody()); BodyScope.Exit(); if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid()) return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope()); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); } /// ParseCXXCasts - This handles the various ways to cast expressions to another /// type. /// /// postfix-expression: [C++ 5.2p1] /// 'dynamic_cast' '<' type-name '>' '(' expression ')' /// 'static_cast' '<' type-name '>' '(' expression ')' /// 'reinterpret_cast' '<' type-name '>' '(' expression ')' /// 'const_cast' '<' type-name '>' '(' expression ')' /// ExprResult Parser::ParseCXXCasts() { tok::TokenKind Kind = Tok.getKind(); const char *CastName = nullptr; // For error messages switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: CastName = "const_cast"; break; case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; case tok::kw_static_cast: CastName = "static_cast"; break; } SourceLocation OpLoc = ConsumeToken(); SourceLocation LAngleBracketLoc = Tok.getLocation(); // Check for "<::" which is parsed as "[:". If found, fix token stream, // diagnose error, suggest fix, and recover parsing. if (Tok.is(tok::l_square) && Tok.getLength() == 2) { Token Next = NextToken(); if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next)) FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); } if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) return ExprError(); // Parse the common declaration-specifiers piece. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); SourceLocation RAngleBracketLoc = Tok.getLocation(); if (ExpectAndConsume(tok::greater)) return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << tok::less); SourceLocation LParenLoc, RParenLoc; BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, CastName)) return ExprError(); ExprResult Result = ParseExpression(); // Match the ')'. T.consumeClose(); if (!Result.isInvalid() && !DeclaratorInfo.isInvalidType()) Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, LAngleBracketLoc, DeclaratorInfo, RAngleBracketLoc, T.getOpenLocation(), Result.get(), T.getCloseLocation()); return Result; } /// ParseCXXTypeid - This handles the C++ typeid expression. /// /// postfix-expression: [C++ 5.2p1] /// 'typeid' '(' expression ')' /// 'typeid' '(' type-id ')' /// ExprResult Parser::ParseCXXTypeid() { assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); SourceLocation OpLoc = ConsumeToken(); SourceLocation LParenLoc, RParenLoc; BalancedDelimiterTracker T(*this, tok::l_paren); // typeid expressions are always parenthesized. if (T.expectAndConsume(diag::err_expected_lparen_after, "typeid")) return ExprError(); LParenLoc = T.getOpenLocation(); ExprResult Result; // C++0x [expr.typeid]p3: // When typeid is applied to an expression other than an lvalue of a // polymorphic class type [...] The expression is an unevaluated // operand (Clause 5). // // Note that we can't tell whether the expression is an lvalue of a // polymorphic class type until after we've parsed the expression; we // speculatively assume the subexpression is unevaluated, and fix it up // later. // // We enter the unevaluated context before trying to determine whether we // have a type-id, because the tentative parse logic will try to resolve // names, and must treat them as unevaluated. EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, Sema::ReuseLambdaContextDecl); if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); // Match the ')'. T.consumeClose(); RParenLoc = T.getCloseLocation(); if (Ty.isInvalid() || RParenLoc.isInvalid()) return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, Ty.get().getAsOpaquePtr(), RParenLoc); } else { Result = ParseExpression(); // Match the ')'. if (Result.isInvalid()) SkipUntil(tok::r_paren, StopAtSemi); else { T.consumeClose(); RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.get(), RParenLoc); } } return Result; } /// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. /// /// '__uuidof' '(' expression ')' /// '__uuidof' '(' type-id ')' /// ExprResult Parser::ParseCXXUuidof() { assert(Tok.is(tok::kw___uuidof) && "Not '__uuidof'!"); SourceLocation OpLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); // __uuidof expressions are always parenthesized. if (T.expectAndConsume(diag::err_expected_lparen_after, "__uuidof")) return ExprError(); ExprResult Result; if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); // Match the ')'. T.consumeClose(); if (Ty.isInvalid()) return ExprError(); Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/true, Ty.get().getAsOpaquePtr(), T.getCloseLocation()); } else { EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); // Match the ')'. if (Result.isInvalid()) SkipUntil(tok::r_paren, StopAtSemi); else { T.consumeClose(); Result = Actions.ActOnCXXUuidof(OpLoc, T.getOpenLocation(), /*isType=*/false, Result.get(), T.getCloseLocation()); } } return Result; } /// \brief Parse a C++ pseudo-destructor expression after the base, /// . or -> operator, and nested-name-specifier have already been /// parsed. /// /// postfix-expression: [C++ 5.2] /// postfix-expression . pseudo-destructor-name /// postfix-expression -> pseudo-destructor-name /// /// pseudo-destructor-name: /// ::[opt] nested-name-specifier[opt] type-name :: ~type-name /// ::[opt] nested-name-specifier template simple-template-id :: /// ~type-name /// ::[opt] nested-name-specifier[opt] ~type-name /// ExprResult Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, ParsedType ObjectType) { // We're parsing either a pseudo-destructor-name or a dependent // member access that has the same form as a // pseudo-destructor-name. We parse both in the same way and let // the action model sort them out. // // Note that the ::[opt] nested-name-specifier[opt] has already // been parsed, and if there was a simple-template-id, it has // been coalesced into a template-id annotation token. UnqualifiedId FirstTypeName; SourceLocation CCLoc; if (Tok.is(tok::identifier)) { FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else if (Tok.is(tok::annot_template_id)) { // FIXME: retrieve TemplateKWLoc from template-id annotation and // store it in the pseudo-dtor node (to be used when instantiating it). FirstTypeName.setTemplateId( (TemplateIdAnnotation *)Tok.getAnnotationValue()); ConsumeToken(); assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else { FirstTypeName.setIdentifier(nullptr, SourceLocation()); } // Parse the tilde. assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); SourceLocation TildeLoc = ConsumeToken(); if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) { DeclSpec DS(AttrFactory); ParseDecltypeSpecifier(DS); if (DS.getTypeSpecType() == TST_error) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, TildeLoc, DS, Tok.is(tok::l_paren)); } if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_destructor_tilde_identifier); return ExprError(); } // Parse the second type. UnqualifiedId SecondTypeName; IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = ConsumeToken(); SecondTypeName.setIdentifier(Name, NameLoc); // If there is a '<', the second type name is a template-id. Parse // it as such. if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId(SS, SourceLocation(), Name, NameLoc, false, ObjectType, SecondTypeName, /*AssumeTemplateName=*/true)) return ExprError(); return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, OpKind, SS, FirstTypeName, CCLoc, TildeLoc, SecondTypeName, Tok.is(tok::l_paren)); } /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. /// /// boolean-literal: [C++ 2.13.5] /// 'true' /// 'false' ExprResult Parser::ParseCXXBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); } /// ParseThrowExpression - This handles the C++ throw expression. /// /// throw-expression: [C++ 15] /// 'throw' assignment-expression[opt] ExprResult Parser::ParseThrowExpression() { assert(Tok.is(tok::kw_throw) && "Not throw!"); SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. // If the current token isn't the start of an assignment-expression, // then the expression is not present. This handles things like: // "C ? throw : (void)42", which is crazy but legal. switch (Tok.getKind()) { // FIXME: move this predicate somewhere common. case tok::semi: case tok::r_paren: case tok::r_square: case tok::r_brace: case tok::colon: case tok::comma: return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, nullptr); default: ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return Expr; return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.get()); } } /// ParseCXXThis - This handles the C++ 'this' pointer. /// /// C++ 9.3.2: In the body of a non-static member function, the keyword this is /// a non-lvalue expression whose value is the address of the object for which /// the function is called. ExprResult Parser::ParseCXXThis() { assert(Tok.is(tok::kw_this) && "Not 'this'!"); SourceLocation ThisLoc = ConsumeToken(); return Actions.ActOnCXXThis(ThisLoc); } /// ParseCXXTypeConstructExpression - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). /// See [C++ 5.2.3]. /// /// postfix-expression: [C++ 5.2p1] /// simple-type-specifier '(' expression-list[opt] ')' /// [C++0x] simple-type-specifier braced-init-list /// typename-specifier '(' expression-list[opt] ')' /// [C++0x] typename-specifier braced-init-list /// ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert((Tok.is(tok::l_paren) || (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))) && "Expected '(' or '{'!"); if (Tok.is(tok::l_brace)) { ExprResult Init = ParseBraceInitializer(); if (Init.isInvalid()) return Init; Expr *InitList = Init.get(); return Actions.ActOnCXXTypeConstructExpr(TypeRep, SourceLocation(), MultiExprArg(&InitList, 1), SourceLocation()); } else { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ExprVector Exprs; CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(Exprs, CommaLocs)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } } // Match the ')'. T.consumeClose(); // TypeRep could be null, if it references an invalid typedef. if (!TypeRep) return ExprError(); assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), Exprs, T.getCloseLocation()); } } /// ParseCXXCondition - if/switch/while condition expression. /// /// condition: /// expression /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// /// \param ExprOut if the condition was parsed as an expression, the parsed /// expression. /// /// \param DeclOut if the condition was parsed as a declaration, the parsed /// declaration. /// /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. /// /// \param ConvertToBoolean Whether the condition expression should be /// converted to a boolean value. /// /// \returns true if there was a parsing, false otherwise. bool Parser::ParseCXXCondition(ExprResult &ExprOut, Decl *&DeclOut, SourceLocation Loc, bool ConvertToBoolean) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); cutOffParsing(); return true; } ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX11Attributes(attrs); if (!isCXXConditionDeclaration()) { ProhibitAttributes(attrs); // Parse the expression. ExprOut = ParseExpression(); // expression DeclOut = nullptr; if (ExprOut.isInvalid()) return true; // If required, convert to a boolean value. if (ConvertToBoolean) ExprOut = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get()); return ExprOut.isInvalid(); } // type-specifier-seq DeclSpec DS(AttrFactory); DS.takeAttributesFrom(attrs); ParseSpecifierQualifierList(DS); // declarator Declarator DeclaratorInfo(DS, Declarator::ConditionContext); ParseDeclarator(DeclaratorInfo); // simple-asm-expr[opt] if (Tok.is(tok::kw_asm)) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopAtSemi); return true; } DeclaratorInfo.setAsmLabel(AsmLabel.get()); DeclaratorInfo.SetRangeEnd(Loc); } // If attributes are present, parse them. MaybeParseGNUAttributes(DeclaratorInfo); // Type-check the declaration itself. DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), DeclaratorInfo); DeclOut = Dcl.get(); ExprOut = ExprError(); // '=' assignment-expression // If a '==' or '+=' is found, suggest a fixit to '='. bool CopyInitialization = isTokenEqualOrEqualTypo(); if (CopyInitialization) ConsumeToken(); ExprResult InitExpr = ExprError(); if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_generalized_initializer_lists); InitExpr = ParseBraceInitializer(); } else if (CopyInitialization) { InitExpr = ParseAssignmentExpression(); } else if (Tok.is(tok::l_paren)) { // This was probably an attempt to initialize the variable. SourceLocation LParen = ConsumeParen(), RParen = LParen; if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) RParen = ConsumeParen(); Diag(DeclOut ? DeclOut->getLocation() : LParen, diag::err_expected_init_in_condition_lparen) << SourceRange(LParen, RParen); } else { Diag(DeclOut ? DeclOut->getLocation() : Tok.getLocation(), diag::err_expected_init_in_condition); } if (!InitExpr.isInvalid()) Actions.AddInitializerToDecl(DeclOut, InitExpr.get(), !CopyInitialization, DS.containsPlaceholderType()); else Actions.ActOnInitializerError(DeclOut); // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). Actions.FinalizeDeclaration(DeclOut); return false; } /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. /// /// simple-type-specifier: /// '::'[opt] nested-name-specifier[opt] type-name /// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] /// char /// wchar_t /// bool /// short /// int /// long /// signed /// unsigned /// float /// double /// void /// [GNU] typeof-specifier /// [C++0x] auto [TODO] /// /// type-name: /// class-name /// enum-name /// typedef-name /// void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetRangeStart(Tok.getLocation()); const char *PrevSpec; unsigned DiagID; SourceLocation Loc = Tok.getLocation(); const clang::PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy(); switch (Tok.getKind()) { case tok::identifier: // foo::bar case tok::coloncolon: // ::foo::bar llvm_unreachable("Annotation token should already be formed!"); default: llvm_unreachable("Not a simple-type-specifier token!"); // type-name case tok::annot_typename: { if (getTypeAnnotation(Tok)) DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, getTypeAnnotation(Tok), Policy); else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // Objective-C supports syntax of the form 'id' where 'id' // is a specific typedef and 'itf' where 'itf' is an // Objective-C interface. If we don't have Objective-C or a '<', this is // just a normal reference to a typedef name. if (Tok.is(tok::less) && getLangOpts().ObjC1) ParseObjCProtocolQualifiers(DS); DS.Finish(Diags, PP, Policy); return; } // builtin types case tok::kw_short: DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_long: DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID, Policy); break; case tok::kw___int64: DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_signed: DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; case tok::kw_unsigned: DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec, DiagID); break; case tok::kw_void: DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_char: DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_int: DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID, Policy); break; case tok::kw___int128: DS.SetTypeSpecType(DeclSpec::TST_int128, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_half: DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_float: DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_double: DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_wchar_t: DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_char16_t: DS.SetTypeSpecType(DeclSpec::TST_char16, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_char32_t: DS.SetTypeSpecType(DeclSpec::TST_char32, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_bool: DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID, Policy); break; case tok::annot_decltype: case tok::kw_decltype: DS.SetRangeEnd(ParseDecltypeSpecifier(DS)); return DS.Finish(Diags, PP, Policy); // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); DS.Finish(Diags, PP, Policy); return; } if (Tok.is(tok::annot_typename)) DS.SetRangeEnd(Tok.getAnnotationEndLoc()); else DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); DS.Finish(Diags, PP, Policy); } /// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ /// [dcl.name]), which is a non-empty sequence of type-specifiers, /// e.g., "const short int". Note that the DeclSpec is *not* finished /// by parsing the type-specifier-seq, because these sequences are /// typically followed by some form of declarator. Returns true and /// emits diagnostics if this is not a type-specifier-seq, false /// otherwise. /// /// type-specifier-seq: [C++ 8.1] /// type-specifier type-specifier-seq[opt] /// bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { ParseSpecifierQualifierList(DS, AS_none, DSC_type_specifier); DS.Finish(Diags, PP, Actions.getASTContext().getPrintingPolicy()); return false; } /// \brief Finish parsing a C++ unqualified-id that is a template-id of /// some form. /// /// This routine is invoked when a '<' is encountered after an identifier or /// operator-function-id is parsed by \c ParseUnqualifiedId() to determine /// whether the unqualified-id is actually a template-id. This routine will /// then parse the template arguments and form the appropriate template-id to /// return to the caller. /// /// \param SS the nested-name-specifier that precedes this template-id, if /// we're actually parsing a qualified-id. /// /// \param Name for constructor and destructor names, this is the actual /// identifier that may be a template-name. /// /// \param NameLoc the location of the class-name in a constructor or /// destructor. /// /// \param EnteringContext whether we're entering the scope of the /// nested-name-specifier. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Id as input, describes the template-name or operator-function-id /// that precedes the '<'. If template arguments were parsed successfully, /// will be updated with the template-id. /// /// \param AssumeTemplateId When true, this routine will assume that the name /// refers to a template without performing name lookup to verify. /// /// \returns true if a parse error occurred, false otherwise. bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Id, bool AssumeTemplateId) { assert((AssumeTemplateId || Tok.is(tok::less)) && "Expected '<' to finish parsing a template-id"); TemplateTy Template; TemplateNameKind TNK = TNK_Non_template; switch (Id.getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: if (AssumeTemplateId) { TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } else { bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), Id, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && ObjectType && IsTemplateArgumentList()) { // We have something like t->getAs(), where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. std::string Name; if (Id.getKind() == UnqualifiedId::IK_Identifier) Name = Id.Identifier->getName(); else { Name = "operator "; if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); else Name += Id.Identifier->getName(); } Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } } break; case UnqualifiedId::IK_ConstructorName: { UnqualifiedId TemplateName; bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); break; } case UnqualifiedId::IK_DestructorName: { UnqualifiedId TemplateName; bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { TNK = Actions.ActOnDependentTemplateName(getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template); if (TNK == TNK_Non_template) return true; } else { TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && !Id.DestructorName.get()) { Diag(NameLoc, diag::err_destructor_template_id) << Name << SS.getRange(); return true; } } break; } default: return false; } if (TNK == TNK_Non_template) return false; // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) return true; if (Id.getKind() == UnqualifiedId::IK_Identifier || Id.getKind() == UnqualifiedId::IK_OperatorFunctionId || Id.getKind() == UnqualifiedId::IK_LiteralOperatorId) { // Form a parsed representation of the template-id to be stored in the // UnqualifiedId. TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds); // FIXME: Store name for literal operator too. if (Id.getKind() == UnqualifiedId::IK_Identifier) { TemplateId->Name = Id.Identifier; TemplateId->Operator = OO_None; TemplateId->TemplateNameLoc = Id.StartLocation; } else { TemplateId->Name = nullptr; TemplateId->Operator = Id.OperatorFunctionId.Operator; TemplateId->TemplateNameLoc = Id.StartLocation; } TemplateId->SS = SS; TemplateId->TemplateKWLoc = TemplateKWLoc; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; Id.setTemplateId(TemplateId); return false; } // Bundle the template arguments together. ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); // Constructor and destructor names. TypeResult Type = Actions.ActOnTemplateIdType(SS, TemplateKWLoc, Template, NameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc, /*IsCtorOrDtorName=*/true); if (Type.isInvalid()) return true; if (Id.getKind() == UnqualifiedId::IK_ConstructorName) Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); else Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); return false; } /// \brief Parse an operator-function-id or conversion-function-id as part /// of a C++ unqualified-id. /// /// This routine is responsible only for parsing the operator-function-id or /// conversion-function-id; it does not handle template arguments in any way. /// /// \code /// operator-function-id: [C++ 13.5] /// 'operator' operator /// /// operator: one of /// new delete new[] delete[] /// + - * / % ^ & | ~ /// ! = < > += -= *= /= %= /// ^= &= |= << >> >>= <<= == != /// <= >= && || ++ -- , ->* -> /// () [] /// /// conversion-function-id: [C++ 12.3.2] /// operator conversion-type-id /// /// conversion-type-id: /// type-specifier-seq conversion-declarator[opt] /// /// conversion-declarator: /// ptr-operator conversion-declarator[opt] /// \endcode /// /// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParsedType ObjectType, UnqualifiedId &Result) { assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); // Consume the 'operator' keyword. SourceLocation KeywordLoc = ConsumeToken(); // Determine what kind of operator name we have. unsigned SymbolIdx = 0; SourceLocation SymbolLocations[3]; OverloadedOperatorKind Op = OO_None; switch (Tok.getKind()) { case tok::kw_new: case tok::kw_delete: { bool isNew = Tok.getKind() == tok::kw_new; // Consume the 'new' or 'delete'. SymbolLocations[SymbolIdx++] = ConsumeToken(); // Check for array new/delete. if (Tok.is(tok::l_square) && (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))) { // Consume the '[' and ']'. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = isNew? OO_Array_New : OO_Array_Delete; } else { Op = isNew? OO_New : OO_Delete; } break; } #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case tok::Token: \ SymbolLocations[SymbolIdx++] = ConsumeToken(); \ Op = OO_##Name; \ break; #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) #include "clang/Basic/OperatorKinds.def" case tok::l_paren: { // Consume the '(' and ')'. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Call; break; } case tok::l_square: { // Consume the '[' and ']'. BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return true; SymbolLocations[SymbolIdx++] = T.getOpenLocation(); SymbolLocations[SymbolIdx++] = T.getCloseLocation(); Op = OO_Subscript; break; } case tok::code_completion: { // Code completion for the operator name. Actions.CodeCompleteOperatorName(getCurScope()); cutOffParsing(); // Don't try to parse any further. return true; } default: break; } if (Op != OO_None) { // We have parsed an operator-function-id. Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); return false; } // Parse a literal-operator-id. // // literal-operator-id: C++11 [over.literal] // operator string-literal identifier // operator user-defined-string-literal if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); SourceLocation DiagLoc; unsigned DiagId = 0; // We're past translation phase 6, so perform string literal concatenation // before checking for "". SmallVector Toks; SmallVector TokLocs; while (isTokenStringLiteral()) { if (!Tok.is(tok::string_literal) && !DiagId) { // C++11 [over.literal]p1: // The string-literal or user-defined-string-literal in a // literal-operator-id shall have no encoding-prefix [...]. DiagLoc = Tok.getLocation(); DiagId = diag::err_literal_operator_string_prefix; } Toks.push_back(Tok); TokLocs.push_back(ConsumeStringToken()); } StringLiteralParser Literal(Toks, PP); if (Literal.hadError) return true; // Grab the literal operator's suffix, which will be either the next token // or a ud-suffix from the string literal. IdentifierInfo *II = nullptr; SourceLocation SuffixLoc; if (!Literal.getUDSuffix().empty()) { II = &PP.getIdentifierTable().get(Literal.getUDSuffix()); SuffixLoc = Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], Literal.getUDSuffixOffset(), PP.getSourceManager(), getLangOpts()); } else if (Tok.is(tok::identifier)) { II = Tok.getIdentifierInfo(); SuffixLoc = ConsumeToken(); TokLocs.push_back(SuffixLoc); } else { Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; return true; } // The string literal must be empty. if (!Literal.GetString().empty() || Literal.Pascal) { // C++11 [over.literal]p1: // The string-literal or user-defined-string-literal in a // literal-operator-id shall [...] contain no characters // other than the implicit terminating '\0'. DiagLoc = TokLocs.front(); DiagId = diag::err_literal_operator_string_not_empty; } if (DiagId) { // This isn't a valid literal-operator-id, but we think we know // what the user meant. Tell them what they should have written. SmallString<32> Str; Str += "\"\" "; Str += II->getName(); Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement( SourceRange(TokLocs.front(), TokLocs.back()), Str); } Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc); return Actions.checkLiteralOperatorId(SS, Result); } // Parse a conversion-function-id. // // conversion-function-id: [C++ 12.3.2] // operator conversion-type-id // // conversion-type-id: // type-specifier-seq conversion-declarator[opt] // // conversion-declarator: // ptr-operator conversion-declarator[opt] // Parse the type-specifier-seq. DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. Declarator D(DS, Declarator::ConversionIdContext); ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr); // Finish up the type. TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D); if (Ty.isInvalid()) return true; // Note that this is a conversion-function-id. Result.setConversionFunctionId(KeywordLoc, Ty.get(), D.getSourceRange().getEnd()); return false; } /// \brief Parse a C++ unqualified-id (or a C identifier), which describes the /// name of an entity. /// /// \code /// unqualified-id: [C++ expr.prim.general] /// identifier /// operator-function-id /// conversion-function-id /// [C++0x] literal-operator-id [TODO] /// ~ class-name /// template-id /// /// \endcode /// /// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the /// nested-name-specifier. /// /// \param AllowDestructorName whether we allow parsing of a destructor name. /// /// \param AllowConstructorName whether we allow parsing a constructor name. /// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// /// \param Result on a successful parse, contains the parsed unqualified-id. /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, ParsedType ObjectType, SourceLocation& TemplateKWLoc, UnqualifiedId &Result) { // Handle 'A::template B'. This is for template-ids which have not // already been annotated by ParseOptionalCXXScopeSpecifier(). bool TemplateSpecified = false; if (getLangOpts().CPlusPlus && Tok.is(tok::kw_template) && (ObjectType || SS.isSet())) { TemplateSpecified = true; TemplateKWLoc = ConsumeToken(); } // unqualified-id: // identifier // template-id (when it hasn't already been annotated) if (Tok.is(tok::identifier)) { // Consume the identifier. IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); if (!getLangOpts().CPlusPlus) { // If we're not in C++, only identifiers matter. Record the // identifier and return. Result.setIdentifier(Id, IdLoc); return false; } if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. ParsedType Ty = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/true, /*NonTrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, IdLoc, IdLoc); } else { // We have parsed an identifier. Result.setIdentifier(Id, IdLoc); } // If the next token is a '<', we may have a template. if (TemplateSpecified || Tok.is(tok::less)) return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, Id, IdLoc, EnteringContext, ObjectType, Result, TemplateSpecified); return false; } // unqualified-id: // template-id (already parsed and annotated) if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If the template-name names the current class, then this is a constructor if (AllowConstructorName && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { if (SS.isSet()) { // C++ [class.qual]p2 specifies that a qualified template-name // is taken as the constructor name where a constructor can be // declared. Thus, the template arguments are extraneous, so // complain about them and remove them entirely. Diag(TemplateId->TemplateNameLoc, diag::err_out_of_line_constructor_template_id) << TemplateId->Name << FixItHint::CreateRemoval( SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); ParsedType Ty = Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), &SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/true, /*NontrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); ConsumeToken(); return false; } Result.setConstructorTemplateId(TemplateId); ConsumeToken(); return false; } // We have already parsed a template-id; consume the annotation token as // our unqualified-id. Result.setTemplateId(TemplateId); TemplateKWLoc = TemplateId->TemplateKWLoc; ConsumeToken(); return false; } // unqualified-id: // operator-function-id // conversion-function-id if (Tok.is(tok::kw_operator)) { if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) return true; // If we have an operator-function-id or a literal-operator-id and the next // token is a '<', we may have a // // template-id: // operator-function-id < template-argument-list[opt] > if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId || Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) && (TemplateSpecified || Tok.is(tok::less))) return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, nullptr, SourceLocation(), EnteringContext, ObjectType, Result, TemplateSpecified); return false; } if (getLangOpts().CPlusPlus && (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { // C++ [expr.unary.op]p10: // There is an ambiguity in the unary-expression ~X(), where X is a // class-name. The ambiguity is resolved in favor of treating ~ as a // unary complement rather than treating ~X as referring to a destructor. // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { Result.setDestructorName(TildeLoc, Type, EndLoc); return false; } return true; } // Parse the class-name. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_destructor_tilde_identifier); return true; } // If the user wrote ~T::T, correct it to T::~T. if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { if (SS.isSet()) { AnnotateScopeToken(SS, /*NewAnnotation*/true); SS.clear(); } if (ParseOptionalCXXScopeSpecifier(SS, ObjectType, EnteringContext)) return true; if (Tok.isNot(tok::identifier) || NextToken().is(tok::coloncolon)) { Diag(TildeLoc, diag::err_destructor_tilde_scope); return true; } // Recover as if the tilde had been written before the identifier. Diag(TildeLoc, diag::err_destructor_tilde_scope) << FixItHint::CreateRemoval(TildeLoc) << FixItHint::CreateInsertion(Tok.getLocation(), "~"); } // Parse the class-name (or template-name in a simple-template-id). IdentifierInfo *ClassName = Tok.getIdentifierInfo(); SourceLocation ClassNameLoc = ConsumeToken(); if (TemplateSpecified || Tok.is(tok::less)) { Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, TemplateKWLoc, ClassName, ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified); } // Note that this is a destructor name. ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, ClassNameLoc, getCurScope(), SS, ObjectType, EnteringContext); if (!Ty) return true; Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); return false; } Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; return true; } /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate /// memory in a typesafe manner and call constructors. /// /// This method is called to parse the new expression after the optional :: has /// been already parsed. If the :: was present, "UseGlobal" is true and "Start" /// is its location. Otherwise, "Start" is the location of the 'new' token. /// /// new-expression: /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// /// new-type-id: /// type-specifier-seq new-declarator[opt] /// [GNU] attributes type-specifier-seq new-declarator[opt] /// /// new-declarator: /// ptr-operator new-declarator[opt] /// direct-new-declarator /// /// new-initializer: /// '(' expression-list[opt] ')' /// [C++0x] braced-init-list /// ExprResult Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_new) && "expected 'new' token"); ConsumeToken(); // Consume 'new' // A '(' now can be a new-placement or the '(' wrapping the type-id in the // second form of new-expression. It can't be a new-type-id. ExprVector PlacementArgs; SourceLocation PlacementLParen, PlacementRParen; SourceRange TypeIdParens; DeclSpec DS(AttrFactory); Declarator DeclaratorInfo(DS, Declarator::CXXNewContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); PlacementLParen = T.getOpenLocation(); if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } T.consumeClose(); PlacementRParen = T.getCloseLocation(); if (PlacementRParen.isInvalid()) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } if (PlacementArgs.empty()) { // Reset the placement locations. There was no placement. TypeIdParens = T.getRange(); PlacementLParen = PlacementRParen = SourceLocation(); } else { // We still need the type. if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); MaybeParseGNUAttributes(DeclaratorInfo); ParseSpecifierQualifierList(DS); DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclarator(DeclaratorInfo); T.consumeClose(); TypeIdParens = T.getRange(); } else { MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); } } } } else { // A new-type-id is a simplified type-id, where essentially the // direct-declarator is replaced by a direct-new-declarator. MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); } } if (DeclaratorInfo.isInvalidType()) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } ExprResult Initializer; if (Tok.is(tok::l_paren)) { SourceLocation ConstructorLParen, ConstructorRParen; ExprVector ConstructorArgs; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ConstructorLParen = T.getOpenLocation(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; if (ParseExpressionList(ConstructorArgs, CommaLocs)) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } } T.consumeClose(); ConstructorRParen = T.getCloseLocation(); if (ConstructorRParen.isInvalid()) { SkipUntil(tok::semi, StopAtSemi | StopBeforeMatch); return ExprError(); } Initializer = Actions.ActOnParenListExpr(ConstructorLParen, ConstructorRParen, ConstructorArgs); } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_generalized_initializer_lists); Initializer = ParseBraceInitializer(); } if (Initializer.isInvalid()) return Initializer; return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, PlacementArgs, PlacementRParen, TypeIdParens, DeclaratorInfo, Initializer.get()); } /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be /// passed to ParseDeclaratorInternal. /// /// direct-new-declarator: /// '[' expression ']' /// direct-new-declarator '[' constant-expression ']' /// void Parser::ParseDirectNewDeclarator(Declarator &D) { // Parse the array dimensions. bool first = true; while (Tok.is(tok::l_square)) { // An array-size expression can't start with a lambda. if (CheckProhibitedCXX11Attribute()) continue; BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); ExprResult Size(first ? ParseExpression() : ParseConstantExpression()); if (Size.isInvalid()) { // Recover SkipUntil(tok::r_square, StopAtSemi); return; } first = false; T.consumeClose(); // Attributes here appertain to the array type. C++11 [expr.new]p5. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Size.get(), T.getOpenLocation(), T.getCloseLocation()), Attrs, T.getCloseLocation()); if (T.getCloseLocation().isInvalid()) return; } } /// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id. /// This ambiguity appears in the syntax of the C++ new operator. /// /// new-expression: /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// new-placement: /// '(' expression-list ')' /// bool Parser::ParseExpressionListOrTypeId( SmallVectorImpl &PlacementArgs, Declarator &D) { // The '(' was already consumed. if (isTypeIdInParens()) { ParseSpecifierQualifierList(D.getMutableDeclSpec()); D.SetSourceRange(D.getDeclSpec().getSourceRange()); ParseDeclarator(D); return D.isInvalidType(); } // It's not a type, it has to be an expression list. // Discard the comma locations - ActOnCXXNew has enough parameters. CommaLocsTy CommaLocs; return ParseExpressionList(PlacementArgs, CommaLocs); } /// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used /// to free memory allocated by new. /// /// This method is called to parse the 'delete' expression after the optional /// '::' has been already parsed. If the '::' was present, "UseGlobal" is true /// and "Start" is its location. Otherwise, "Start" is the location of the /// 'delete' token. /// /// delete-expression: /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression ExprResult Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword"); ConsumeToken(); // Consume 'delete' // Array delete? bool ArrayDelete = false; if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) { // C++11 [expr.delete]p1: // Whenever the delete keyword is followed by empty square brackets, it // shall be interpreted as [array delete]. // [Footnote: A lambda expression with a lambda-introducer that consists // of empty square brackets can follow the delete keyword if // the lambda expression is enclosed in parentheses.] // FIXME: Produce a better diagnostic if the '[]' is unambiguously a // lambda-introducer. ArrayDelete = true; BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return ExprError(); } ExprResult Operand(ParseCastExpression(false)); if (Operand.isInvalid()) return Operand; return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.get()); } static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { switch (kind) { default: llvm_unreachable("Not a known type trait"); #define TYPE_TRAIT_1(Spelling, Name, Key) \ case tok::kw_ ## Spelling: return UTT_ ## Name; #define TYPE_TRAIT_2(Spelling, Name, Key) \ case tok::kw_ ## Spelling: return BTT_ ## Name; #include "clang/Basic/TokenKinds.def" #define TYPE_TRAIT_N(Spelling, Name, Key) \ case tok::kw_ ## Spelling: return TT_ ## Name; #include "clang/Basic/TokenKinds.def" } } static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known binary type trait"); case tok::kw___array_rank: return ATT_ArrayRank; case tok::kw___array_extent: return ATT_ArrayExtent; } } static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known unary expression trait."); case tok::kw___is_lvalue_expr: return ET_IsLValueExpr; case tok::kw___is_rvalue_expr: return ET_IsRValueExpr; } } static unsigned TypeTraitArity(tok::TokenKind kind) { switch (kind) { default: llvm_unreachable("Not a known type trait"); #define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N; #include "clang/Basic/TokenKinds.def" } } /// \brief Parse the built-in type-trait pseudo-functions that allow /// implementation of the TR1/C++11 type traits templates. /// /// primary-expression: /// unary-type-trait '(' type-id ')' /// binary-type-trait '(' type-id ',' type-id ')' /// type-trait '(' type-id-seq ')' /// /// type-id-seq: /// type-id ...[opt] type-id-seq[opt] /// ExprResult Parser::ParseTypeTrait() { tok::TokenKind Kind = Tok.getKind(); unsigned Arity = TypeTraitArity(Kind); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Parens.expectAndConsume()) return ExprError(); SmallVector Args; do { // Parse the next type. TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); } // Parse the ellipsis, if present. if (Tok.is(tok::ellipsis)) { Ty = Actions.ActOnPackExpansion(Ty.get(), ConsumeToken()); if (Ty.isInvalid()) { Parens.skipToEnd(); return ExprError(); } } // Add this type to the list of arguments. Args.push_back(Ty.get()); } while (TryConsumeToken(tok::comma)); if (Parens.consumeClose()) return ExprError(); SourceLocation EndLoc = Parens.getCloseLocation(); if (Arity && Args.size() != Arity) { Diag(EndLoc, diag::err_type_trait_arity) << Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc); return ExprError(); } if (!Arity && Args.empty()) { Diag(EndLoc, diag::err_type_trait_arity) << 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc); return ExprError(); } return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc); } /// ParseArrayTypeTrait - Parse the built-in array type-trait /// pseudo-functions. /// /// primary-expression: /// [Embarcadero] '__array_rank' '(' type-id ')' /// [Embarcadero] '__array_extent' '(' type-id ',' expression ')' /// ExprResult Parser::ParseArrayTypeTrait() { ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return ExprError(); TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { SkipUntil(tok::comma, StopAtSemi); SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } switch (ATT) { case ATT_ArrayRank: { T.consumeClose(); return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), nullptr, T.getCloseLocation()); } case ATT_ArrayExtent: { if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } ExprResult DimExpr = ParseExpression(); T.consumeClose(); return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), T.getCloseLocation()); } } llvm_unreachable("Invalid ArrayTypeTrait!"); } /// ParseExpressionTrait - Parse built-in expression-trait /// pseudo-functions like __is_lvalue_expr( xxx ). /// /// primary-expression: /// [Embarcadero] expression-trait '(' expression ')' /// ExprResult Parser::ParseExpressionTrait() { ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return ExprError(); ExprResult Expr = ParseExpression(); T.consumeClose(); return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), T.getCloseLocation()); } /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a /// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate /// based on the context past the parens. ExprResult Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ParsedType &CastTy, BalancedDelimiterTracker &Tracker, ColonProtectionRAIIObject &ColonProt) { assert(getLangOpts().CPlusPlus && "Should only be called for C++!"); assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); assert(isTypeIdInParens() && "Not a type-id!"); ExprResult Result(true); CastTy = ParsedType(); // We need to disambiguate a very ugly part of the C++ syntax: // // (T())x; - type-id // (T())*x; - type-id // (T())/x; - expression // (T()); - expression // // The bad news is that we cannot use the specialized tentative parser, since // it can only verify that the thing inside the parens can be parsed as // type-id, it is not useful for determining the context past the parens. // // The good news is that the parser can disambiguate this part without // making any unnecessary Action calls. // // It uses a scheme similar to parsing inline methods. The parenthesized // tokens are cached, the context that follows is determined (possibly by // parsing a cast-expression), and then we re-introduce the cached tokens // into the token stream and parse them appropriately. ParenParseOption ParseAs; CachedTokens Toks; // Store the tokens of the parentheses. We will parse them after we determine // the context that follows them. if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { // We didn't find the ')' we expected. Tracker.consumeClose(); return ExprError(); } if (Tok.is(tok::l_brace)) { ParseAs = CompoundLiteral; } else { bool NotCastExpr; if (Tok.is(tok::l_paren) && NextToken().is(tok::r_paren)) { NotCastExpr = true; } else { // Try parsing the cast-expression that may follow. // If it is not a cast-expression, NotCastExpr will be true and no token // will be consumed. ColonProt.restore(); Result = ParseCastExpression(false/*isUnaryExpression*/, false/*isAddressofOperand*/, NotCastExpr, // type-id has priority. IsTypeCast); } // If we parsed a cast-expression, it's really a type-id, otherwise it's // an expression. ParseAs = NotCastExpr ? SimpleExpr : CastExpr; } // The current token should go after the cached tokens. Toks.push_back(Tok); // Re-enter the stored parenthesized tokens into the token stream, so we may // parse them now. PP.EnterTokenStream(Toks.data(), Toks.size(), true/*DisableMacroExpansion*/, false/*OwnsTokens*/); // Drop the current token and bring the first cached one. It's the same token // as when we entered this function. ConsumeAnyToken(); if (ParseAs >= CompoundLiteral) { // Parse the type declarator. DeclSpec DS(AttrFactory); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); { ColonProtectionRAIIObject InnerColonProtection(*this); ParseSpecifierQualifierList(DS); ParseDeclarator(DeclaratorInfo); } // Match the ')'. Tracker.consumeClose(); ColonProt.restore(); if (ParseAs == CompoundLiteral) { ExprType = CompoundLiteral; if (DeclaratorInfo.isInvalidType()) return ExprError(); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); return ParseCompoundLiteralExpression(Ty.get(), Tracker.getOpenLocation(), Tracker.getCloseLocation()); } // We parsed '(' type-id ')' and the thing after it wasn't a '{'. assert(ParseAs == CastExpr); if (DeclaratorInfo.isInvalidType()) return ExprError(); // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(), DeclaratorInfo, CastTy, Tracker.getCloseLocation(), Result.get()); return Result; } // Not a compound literal, and not followed by a cast-expression. assert(ParseAs == SimpleExpr); ExprType = SimpleExpr; Result = ParseExpression(); if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(Tracker.getOpenLocation(), Tok.getLocation(), Result.get()); // Match the ')'. if (Result.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Tracker.consumeClose(); return Result; } Index: vendor/clang/dist/lib/Sema/SemaDecl.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 278753) +++ vendor/clang/dist/lib/Sema/SemaDecl.cpp (revision 278754) @@ -1,13932 +1,13940 @@ //===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements semantic analysis for declarations. // //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CommentDiagnostic.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. #include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Preprocessor.h" // Included for isCodeCompletionEnabled() #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" #include #include #include using namespace clang; using namespace sema; Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { if (OwnedType) { Decl *Group[2] = { OwnedType, Ptr }; return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2)); } return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } namespace { class TypeNameValidatorCCC : public CorrectionCandidateCallback { public: TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false, bool AllowTemplates=false) : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), AllowClassTemplates(AllowTemplates) { WantExpressionKeywords = false; WantCXXNamedCasts = false; WantRemainingKeywords = false; } bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) { bool IsType = isa(ND) || isa(ND); bool AllowedTemplate = AllowClassTemplates && isa(ND); return (IsType || AllowedTemplate) && (AllowInvalidDecl || !ND->isInvalidDecl()); } return !WantClassName && candidate.isKeyword(); } private: bool AllowInvalidDecl; bool WantClassName; bool AllowClassTemplates; }; } /// \brief Determine whether the token kind starts a simple-type-specifier. bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { switch (Kind) { // FIXME: Take into account the current language when deciding whether a // token kind is a valid type specifier case tok::kw_short: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: case tok::kw_char: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: return true; case tok::annot_typename: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_typeof: case tok::annot_decltype: case tok::kw_decltype: return getLangOpts().CPlusPlus; default: break; } return false; } static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc) { // Find the first parent class template context, if any. // FIXME: Perform the lookup in all enclosing class templates. const CXXRecordDecl *RD = nullptr; for (DeclContext *DC = S.CurContext; DC; DC = DC->getParent()) { RD = dyn_cast(DC); if (RD && RD->getDescribedClassTemplate()) break; } if (!RD) return ParsedType(); // Look for type decls in dependent base classes that have known primary // templates. bool FoundTypeDecl = false; for (const auto &Base : RD->bases()) { auto *TST = Base.getType()->getAs(); if (!TST || !TST->isDependentType()) continue; auto *TD = TST->getTemplateName().getAsTemplateDecl(); if (!TD) continue; auto *BasePrimaryTemplate = dyn_cast_or_null(TD->getTemplatedDecl()); if (!BasePrimaryTemplate) continue; // FIXME: Allow lookup into non-dependent bases of dependent bases, possibly // by calling or integrating with the main LookupQualifiedName mechanism. for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) { if (FoundTypeDecl) return ParsedType(); FoundTypeDecl = isa(ND); if (!FoundTypeDecl) return ParsedType(); } } if (!FoundTypeDecl) return ParsedType(); // We found some types in dependent base classes. Recover as if the user // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the // lookup during template instantiation. S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II; ASTContext &Context = S.Context; auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false, cast(Context.getRecordType(RD))); QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II); CXXScopeSpec SS; SS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// \brief If the identifier refers to a type name within this scope, /// return the declaration of that type. /// /// This routine performs ordinary name lookup of the identifier II /// within the given scope, with optional C++ scope specifier SS, to /// determine whether the name refers to a type. If so, returns an /// opaque pointer (actually a QualType) corresponding to that /// type. Otherwise, returns NULL. ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, IdentifierInfo **CorrectedII) { // Determine where we will perform name lookup. DeclContext *LookupCtx = nullptr; if (ObjectTypePtr) { QualType ObjectType = ObjectTypePtr.get(); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); } else if (SS && SS->isNotEmpty()) { LookupCtx = computeDeclContext(*SS, false); if (!LookupCtx) { if (isDependentScopeSpecifier(*SS)) { // C++ [temp.res]p3: // A qualified-id that refers to a type and in which the // nested-name-specifier depends on a template-parameter (14.6.2) // shall be prefixed by the keyword typename to indicate that the // qualified-id denotes a type, forming an // elaborated-type-specifier (7.1.5.3). // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. if (!isClassName && !IsCtorOrDtorName) return ParsedType(); // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } return ParsedType(); } if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) return ParsedType(); } // FIXME: LookupNestedNameSpecifierName isn't the right kind of // lookup for class-names. LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName : LookupOrdinaryName; LookupResult Result(*this, &II, NameLoc, Kind); if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Result, LookupCtx); if (ObjectTypePtr && Result.empty()) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up // in the context of the entire postfix-expression. If the type T of // the object expression is of a class type C, the type-name is also // looked up in the scope of class C. At least one of the lookups shall // find a name that refers to (possibly cv-qualified) T. LookupName(Result, S); } } else { // Perform unqualified name lookup. LookupName(Result, S); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, II, NameLoc)) return TypeInBase; } } NamedDecl *IIDecl = nullptr; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { TypoCorrection Correction = CorrectTypo( Result.getLookupNameInfo(), Kind, S, SS, llvm::make_unique(true, isClassName), CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; UnqualifiedId TemplateName; TemplateName.setIdentifier(NewII, NameLoc); NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); CXXScopeSpec NewSS, *NewSSPtr = SS; if (SS && NNS) { NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NewSSPtr = &NewSS; } if (Correction && (NNS || NewII != &II) && // Ignore a correction to a template type as the to-be-corrected // identifier is not a template (typo correction for template names // is handled elsewhere). !(getLangOpts().CPlusPlus && NewSSPtr && isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(), false, Template, MemberOfUnknownSpecialization))) { ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, WantNontrivialTypeSourceInfo); if (Ty) { diagnoseTypo(Correction, PDiag(diag::err_unknown_type_or_class_name_suggest) << Result.getLookupName() << isClassName); if (SS && NNS) SS->MakeTrivial(Context, NNS, SourceRange(NameLoc)); *CorrectedII = NewII; return Ty; } } } // If typo correction failed or was not performed, fall through case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); return ParsedType(); case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll // do the lookup again when looking for an object, and we can // diagnose the error then. If we don't do this, then the error // about hiding the type will be immediately followed by an error // that only makes sense if the identifier was treated like a type. if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { Result.suppressDiagnostics(); return ParsedType(); } // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); Res != ResEnd; ++Res) { if (isa(*Res) || isa(*Res)) { if (!IIDecl || (*Res)->getLocation().getRawEncoding() < IIDecl->getLocation().getRawEncoding()) IIDecl = *Res; } } if (!IIDecl) { // None of the entities we found is a type, so there is no way // to even assume that the result is a type. In this case, don't // complain about the ambiguity. The parser will either try to // perform this lookup again (e.g., as an object name), which // will produce the ambiguity, or will complain that it expected // a type name. Result.suppressDiagnostics(); return ParsedType(); } // We found a type within the ambiguous lookup; diagnose the // ambiguity and then return that type. This might be the right // answer, or it might not be, but it suppresses any attempt to // perform the name lookup again. break; case LookupResult::Found: IIDecl = Result.getFoundDecl(); break; } assert(IIDecl && "Didn't find decl"); QualType T; if (TypeDecl *TD = dyn_cast(IIDecl)) { DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); // NOTE: avoid constructing an ElaboratedType(Loc) if this is a // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Expr or Decl node). if (SS && SS->isNotEmpty() && !IsCtorOrDtorName) { if (WantNontrivialTypeSourceInfo) { // Construct a type with type-source information. TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = getElaboratedType(ETK_None, *SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } else { T = getElaboratedType(ETK_None, *SS, T); } } } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); } if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return ParsedType(); } return ParsedType::make(T); } // Builds a fake NNS for the given decl context. static NestedNameSpecifier * synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { for (;; DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); auto *ND = dyn_cast(DC); if (ND && !ND->isInline() && !ND->isAnonymousNamespace()) return NestedNameSpecifier::Create(Context, nullptr, ND); else if (auto *RD = dyn_cast(DC)) return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl()); else if (isa(DC)) return NestedNameSpecifier::GlobalSpecifier(Context); } llvm_unreachable("something isn't in TU scope?"); } ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II, SourceLocation NameLoc) { // Accepting an undeclared identifier as a default argument for a template // type parameter is a Microsoft extension. Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; // Build a fake DependentNameType that will perform lookup into CurContext at // instantiation time. The name specifier isn't dependent, so template // instantiation won't transform it. It will retry the lookup, however. NestedNameSpecifier *NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext); QualType T = Context.getDependentNameType(ETK_None, NNS, &II); // Build type location information. We synthesized the qualifier, so we have // to build a fake NestedNameSpecifierLoc. NestedNameSpecifierLocBuilder NNSLocBuilder; NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(QualifierLoc); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, /// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose /// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); LookupName(R, S, false); R.suppressDiagnostics(); if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = R.getAsSingle()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; } } return DeclSpec::TST_unspecified; } /// isMicrosoftMissingTypename - In Microsoft mode, within class scope, /// if a CXXScopeSpec's type is equal to the type of one of the base classes /// then downgrade the missing typename error to a warning. /// This is needed for MSVC compatibility; Example: /// @code /// template class A { /// public: /// typedef int TYPE; /// }; /// template class B : public A { /// public: /// A::TYPE a; // no typename required because A is a base class. /// }; /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) return true; const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); for (const auto &Base : RD->bases()) if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType())) return true; return S->isFunctionPrototypeScope(); } return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool AllowClassTemplates) { // We don't have anything to suggest (yet). SuggestedType = ParsedType(); // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, llvm::make_unique( false, false, AllowClassTemplates), CTK_ErrorRecovery)) { if (Corrected.isKeyword()) { // We corrected to a keyword. diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II); II = Corrected.getCorrectionAsIdentifierInfo(); } else { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) { diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II); } else if (DeclContext *DC = computeDeclContext(*SS, false)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && II->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(diag::err_unknown_nested_typename_suggest) << II << DC << DroppedSpecifier << SS->getRange()); } else { llvm_unreachable("could not have corrected a typo here"); } CXXScopeSpec tmpSS; if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(IILoc)); SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false, false, ParsedType(), /*IsCtorOrDtorName=*/false, /*NonTrivialTypeSourceInfo=*/true); } return; } if (getLangOpts().CPlusPlus) { // See if II is a class template that the user forgot to pass arguments to. UnqualifiedId Name; Name.setIdentifier(II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, Name, ParsedType(), true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.get(); Diag(IILoc, diag::err_template_missing_args) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { Diag(TplDecl->getLocation(), diag::note_template_decl_here) << TplDecl->getTemplateParameters()->getSourceRange(); } return; } } // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? if (!SS || (!SS->isSet() && !SS->isInvalid())) Diag(IILoc, diag::err_unknown_typename) << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_typename_nested_not_found) << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) DiagID = diag::ext_typename_missing; Diag(SS->getRange().getBegin(), DiagID) << SS->getScopeRep() << II->getName() << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); } else { assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); } } /// \brief Determine whether the given result set contains either a type name /// or static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus && NextToken.is(tok::less); for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (isa(*I) || isa(*I)) return true; if (CheckTemplate && isa(*I)) return true; } return false; } static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); SemaRef.LookupParsedName(R, S, &SS); if (TagDecl *Tag = R.getAsSingle()) { StringRef FixItTagName; switch (Tag->getTagKind()) { case TTK_Class: FixItTagName = "class "; break; case TTK_Enum: FixItTagName = "enum "; break; case TTK_Struct: FixItTagName = "struct "; break; case TTK_Interface: FixItTagName = "__interface "; break; case TTK_Union: FixItTagName = "union "; break; } StringRef TagName = FixItTagName.drop_back(); SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag) << Name << TagName << SemaRef.getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); for (LookupResult::iterator I = Result.begin(), IEnd = Result.end(); I != IEnd; ++I) SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) << Name << TagName; // Replace lookup results with just the tag decl. Result.clear(Sema::LookupTagName); SemaRef.LookupParsedName(Result, S, &SS); return true; } return false; } /// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, QualType T, SourceLocation NameLoc) { ASTContext &Context = S.Context; TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = S.getElaboratedType(ETK_None, SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, bool IsAddressOfOperand, std::unique_ptr CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); if (NextToken.is(tok::coloncolon)) { BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(), QualType(), false, SS, nullptr, false); } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc)) return TypeInBase; } // Perform lookup for Objective-C instance variables (including automatically // synthesized instance variables), if we're in an Objective-C method. // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { ExprResult E = LookupInObjCMethod(Result, S, Name, true); if (E.get() || E.isInvalid()) return E; } bool SecondTry = false; bool IsFilteredTemplateName = false; Corrected: switch (Result.getResultKind()) { case LookupResult::NotFound: // If an unqualified-id is followed by a '(', then we have a function // call. if (!SS.isSet() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? if (getLangOpts().CPlusPlus) return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); // C90 6.3.2.2: // If the expression that precedes the parenthesized argument list in a // function call consists solely of an identifier, and if no // declaration is visible for this identifier, the identifier is // implicitly declared exactly as if, in the innermost block containing // the function call, the declaration // // extern int identifier (); // // appeared. // // We also allow this in C99 as an extension. if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) { Result.addDecl(D); Result.resolveKind(); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false); } } // In C, we first see whether there is a tag type by the same name, in // which case it's likely that the user just forget to write "enum", // "struct", or "union". if (!getLangOpts().CPlusPlus && !SecondTry && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { break; } // Perform typo correction to determine if there is another name that is // close to this name. if (!SecondTry && CCC) { SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, &SS, std::move(CCC), CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; NamedDecl *FirstDecl = Corrected.getCorrectionDecl(); NamedDecl *UnderlyingFirstDecl = FirstDecl? FirstDecl->getUnderlyingDecl() : nullptr; if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && UnderlyingFirstDecl && isa(UnderlyingFirstDecl)) { UnqualifiedDiag = diag::err_no_template_suggest; QualifiedDiag = diag::err_no_member_template_suggest; } else if (UnderlyingFirstDecl && (isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl))) { UnqualifiedDiag = diag::err_unknown_typename_suggest; QualifiedDiag = diag::err_unknown_nested_typename_suggest; } if (SS.isEmpty()) { diagnoseTypo(Corrected, PDiag(UnqualifiedDiag) << Name); } else {// FIXME: is this even reachable? Test it. std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(QualifiedDiag) << Name << computeDeclContext(SS, false) << DroppedSpecifier << SS.getRange()); } // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); // Typo correction corrected to a keyword. if (Corrected.isKeyword()) return Name; // Also update the LookupResult... // FIXME: This should probably go away at some point Result.clear(); Result.setLookupName(Corrected.getCorrection()); if (FirstDecl) Result.addDecl(FirstDecl); // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to // reference the ivar. // FIXME: This is a gross hack. if (ObjCIvarDecl *Ivar = Result.getAsSingle()) { Result.clear(); ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); return E; } goto Corrected; } } // We failed to correct; just fall through and let the parser deal with it. Result.suppressDiagnostics(); return NameClassification::Unknown(); case LookupResult::NotFoundInCurrentInstantiation: { // We performed name lookup into the current instantiation, and there were // dependent bases, so we treat this result the same way as any other // dependent nested-name-specifier. // C++ [temp.res]p2: // A name used in a template declaration or definition and that is // dependent on a template-parameter is assumed not to name a type // unless the applicable name lookup finds a type name or the name is // qualified by the keyword typename. // // FIXME: If the next token is '<', we might want to ask the parser to // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, IsAddressOfOperand, /*TemplateArgs=*/nullptr); } case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; case LookupResult::Ambiguous: if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && hasAnyAcceptableTemplateNames(Result)) { // C++ [temp.local]p3: // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name // is followed by a template-argument-list, the reference refers to the // class template itself and not a specialization thereof, and is not // ambiguous. // // This filtering can make an ambiguous result into an unambiguous one, // so try again after filtering out template names. FilterAcceptableTemplateNames(Result); if (!Result.isAmbiguous()) { IsFilteredTemplateName = true; break; } } // Diagnose the ambiguity and return an error. return NameClassification::Error(); } if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of // overloaded functions any member of which is a function template if // this is followed by a <, the < is always taken as the delimiter of a // template-argument-list and never as the less-than operator. if (!IsFilteredTemplateName) FilterAcceptableTemplateNames(Result); if (!Result.empty()) { bool IsFunctionTemplate; bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; Template = Context.getOverloadedTemplateName(Result.begin(), Result.end()); } else { TemplateDecl *TD = cast((*Result.begin())->getUnderlyingDecl()); IsFunctionTemplate = isa(TD); IsVarTemplate = isa(TD); if (SS.isSet() && !SS.isInvalid()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, TD); else Template = TemplateName(TD); } if (IsFunctionTemplate) { // Function templates always go through overload resolution, at which // point we'll perform the various checks (e.g., accessibility) we need // to based on which function we selected. Result.suppressDiagnostics(); return NameClassification::FunctionTemplate(Template); } return IsVarTemplate ? NameClassification::VarTemplate(Template) : NameClassification::TypeTemplate(Template); } } NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } ObjCInterfaceDecl *Class = dyn_cast(FirstDecl); if (!Class) { // FIXME: It's unfortunate that we don't have a Type node for handling this. if (ObjCCompatibleAliasDecl *Alias = dyn_cast(FirstDecl)) Class = Alias->getClassInterface(); } if (Class) { DiagnoseUseOfDecl(Class, NameLoc); if (NextToken.is(tok::period)) { // Interface. is parsed as a property reference expression. // Just return "unknown" as a fall-through for now. Result.suppressDiagnostics(); return NameClassification::Unknown(); } QualType T = Context.getObjCInterfaceType(Class); return ParsedType::make(T); } // We can have a type template here if we're classifying a template argument. if (isa(FirstDecl) && !isa(FirstDecl)) return NameClassification::TypeTemplate( TemplateName(cast(FirstDecl))); // Check for a tag type hidden by a non-type decl in a few cases where it // seems likely a type is wanted instead of the non-type that was found. bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->getUnderlyingDecl()->isFunctionOrFunctionTemplate())) && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { TypeDecl *Type = Result.getAsSingle(); DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); } // Determines the context to return to after temporarily entering a // context. This depends in an unnecessarily complicated way on the // exact ordering of callbacks from the parser. DeclContext *Sema::getContainingDC(DeclContext *DC) { // Functions defined inline within classes aren't parsed until we've // finished parsing the top-level class, so the top-level class is // the context we'll need to return to. // A Lambda call operator whose parent is a class must not be treated // as an inline member function. A Lambda can be used legally // either as an in-class member initializer or a default argument. These // are parsed once the class has been marked complete and so the containing // context would be the nested class (when the lambda is defined in one); // If the class is not complete, then the lambda is being used in an // ill-formed fashion (such as to specify the width of a bit-field, or // in an array-bound) - in which case we still want to return the // lexically containing DC (which could be a nested class). if (isa(DC) && !isLambdaCallOperator(DC)) { DC = DC->getLexicalParent(); // A function not defined within a class will always return to its // lexical context. if (!isa(DC)) return DC; // A C++ inline method/friend is parsed *after* the topmost class // it was declared in is fully parsed ("complete"); the topmost // class is the context we need to return to. while (CXXRecordDecl *RD = dyn_cast(DC->getLexicalParent())) DC = RD; // Return the declaration context of the topmost class the inline method is // declared in. return DC; } return DC->getLexicalParent(); } void Sema::PushDeclContext(Scope *S, DeclContext *DC) { assert(getContainingDC(DC) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; S->setEntity(DC); } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); CurContext = getContainingDC(CurContext); assert(CurContext && "Popped translation unit!"); } /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. /// void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { // C++0x [basic.lookup.unqual]p13: // A name used in the definition of a static data member of class // X (after the qualified-id of the static member) is looked up as // if the name was used in a member function of X. // C++0x [basic.lookup.unqual]p14: // If a variable member of a namespace is defined outside of the // scope of its namespace then any name used in the definition of // the variable member (after the declarator-id) is looked up as // if the definition of the variable member occurred in its // namespace. // Both of these imply that we should push a scope whose context // is the semantic context of the declaration. We can't use // PushDeclContext here because that context is not necessarily // lexically contained in the current context. Fortunately, // the containing scope should have the appropriate information. assert(!S->getEntity() && "scope already has entity"); #ifndef NDEBUG Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch"); #endif CurContext = DC; S->setEntity(DC); } void Sema::ExitDeclaratorContext(Scope *S) { assert(S->getEntity() == CurContext && "Context imbalance!"); // Switch back to the lexical context. The safety of this is // enforced by an assert in EnterDeclaratorContext. Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); CurContext = Ancestor->getEntity(); // We don't need to do anything with the scope, which is going to // disappear. } void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. FunctionDecl *FD = D->getAsFunction(); if (!FD) return; // Same implementation as PushDeclContext, but enters the context // from the lexical parent, rather than the top-level class. assert(CurContext == FD->getLexicalParent() && "The next DeclContext should be lexically contained in the current one."); CurContext = FD; S->setEntity(CurContext); for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) { ParmVarDecl *Param = FD->getParamDecl(P); // If the parameter has an identifier, then add it to the scope if (Param->getIdentifier()) { S->AddDecl(Param); IdResolver.AddDecl(Param); } } } void Sema::ActOnExitFunctionContext() { // Same implementation as PopDeclContext, but returns to the lexical parent, // rather than the top-level class. assert(CurContext && "DeclContext imbalance!"); CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } /// \brief Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// /// This routine determines whether overloading is possible, not /// whether some new function is actually an overload. It will return /// true in C++ (where we can always provide overloads) or, as an /// extension, in C when the previous function is already an /// overloaded function declaration or has the "overloadable" /// attribute. static bool AllowOverloadingOfFunction(LookupResult &Previous, ASTContext &Context) { if (Context.getLangOpts().CPlusPlus) return true; if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; return (Previous.getResultKind() == LookupResult::Found && Previous.getFoundDecl()->hasAttr()); } /// Add this decl to the scope shadowed decl chains. void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Move up the scope chain until we find the nearest enclosing // non-transparent context. The declaration will be introduced into this // scope. while (S->getEntity() && S->getEntity()->isTransparentContext()) S = S->getParent(); // Add scoped declarations into their context, so that they can be // found later. Declarations without a context won't be inserted // into any context. if (AddToContext) CurContext->addDecl(D); // Out-of-line definitions shouldn't be pushed into scope in C++, unless they // are function-local declarations. if (getLangOpts().CPlusPlus && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( D->getLexicalDeclContext()->getRedeclContext()) && !D->getLexicalDeclContext()->isFunctionOrMethod()) return; // Template instantiations should also not be pushed into scope. if (isa(D) && cast(D)->isFunctionTemplateSpecialization()) return; // If this replaces anything in the current scope, IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); for (; I != IEnd; ++I) { if (S->isDeclScope(*I) && D->declarationReplaces(*I)) { S->RemoveDecl(*I); IdResolver.RemoveDecl(*I); // Should only need to replace one decl. break; } } S->AddDecl(D); if (isa(D) && !cast(D)->isGnuLocal()) { // Implicitly-generated labels may end up getting generated in an order that // isn't strictly lexical, which breaks name lookup. Be careful to insert // the label at the appropriate place in the identifier chain. for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) { DeclContext *IDC = (*I)->getLexicalDeclContext()->getRedeclContext(); if (IDC == CurContext) { if (!S->isDeclScope(*I)) continue; } else if (IDC->Encloses(CurContext)) break; } IdResolver.InsertDeclAfter(I, D); } else { IdResolver.AddDecl(D); } } void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope) TUScope->AddDecl(D); } bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) { return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace); } Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { DeclContext *TargetDC = DC->getPrimaryContext(); do { if (DeclContext *ScopeDC = S->getEntity()) if (ScopeDC->getPrimaryContext() == TargetDC) return S; } while ((S = S->getParent())); return nullptr; } static bool isOutOfScopePreviousDeclaration(NamedDecl *, DeclContext*, ASTContext&); /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (isDeclInScope(D, Ctx, S, AllowInlineNamespace)) continue; if (ConsiderLinkage && isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); } F.done(); } static bool isUsingDecl(NamedDecl *D) { return isa(D) || isa(D) || isa(D); } /// Removes using shadow declarations from the lookup results. static void RemoveUsingDecls(LookupResult &R) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) if (isUsingDecl(F.next())) F.erase(); F.done(); } /// \brief Check for this common pattern: /// @code /// class S { /// S(const S&); // DO NOT IMPLEMENT /// void operator=(const S&); // DO NOT IMPLEMENT /// }; /// @endcode static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { // FIXME: Should check for private access too but access is set after we get // the decl here. if (D->doesThisDeclarationHaveABody()) return false; if (const CXXConstructorDecl *CD = dyn_cast(D)) return CD->isCopyConstructor(); if (const CXXMethodDecl *Method = dyn_cast(D)) return Method->isCopyAssignmentOperator(); return false; } // We need this to handle // // typedef struct { // void *foo() { return 0; } // } A; // // When we see foo we don't know if after the typedef we will get 'A' or '*A' // for example. If 'A', foo will have external linkage. If we have '*A', // foo will have no linkage. Since we can't know until we get to the end // of the typedef, this function finds out if D might have non-external linkage. // Callers should verify at the end of the TU if it D has external linkage or // not. bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { const DeclContext *DC = D->getDeclContext(); while (!DC->isTranslationUnit()) { if (const RecordDecl *RD = dyn_cast(DC)){ if (!RD->hasNameForLinkage()) return true; } DC = DC->getParent(); } return !D->isExternallyVisible(); } // FIXME: This needs to be refactored; some other isInMainFile users want // these semantics. static bool isMainFileLoc(const Sema &S, SourceLocation Loc) { if (S.TUKind != TU_Complete) return false; return S.SourceMgr.isInMainFile(Loc); } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { assert(D); if (D->isInvalidDecl() || D->isUsed() || D->hasAttr()) return false; // Ignore all entities declared within templates, and out-of-line definitions // of members of class templates. if (D->getDeclContext()->isDependentContext() || D->getLexicalDeclContext()->isDependentContext()) return false; if (const FunctionDecl *FD = dyn_cast(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) return false; } else { // 'static inline' functions are defined in headers; don't warn. if (FD->isInlined() && !isMainFileLoc(*this, FD->getLocation())) return false; } if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast(D)) { // Constants and utility variables are defined in headers with internal // linkage; don't warn. (Unlike functions, there isn't a convenient marker // like "inline".) if (!isMainFileLoc(*this, VD->getLocation())) return false; if (Context.DeclMustBeEmitted(VD)) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; } else { return false; } // Only warn for unused decls internal to the translation unit. // FIXME: This seems like a bogus check; it suppresses -Wunused-function // for inline functions defined in the main source file, for instance. return mightHaveNonExternalLinkage(D); } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; if (const FunctionDecl *FD = dyn_cast(D)) { const FunctionDecl *First = FD->getFirstDecl(); if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *First = VD->getFirstDecl(); if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (ShouldWarnIfUnusedFileScopedDecl(D)) UnusedFileScopedDecls.push_back(D); } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) return false; if (D->isReferenced() || D->isUsed() || D->hasAttr() || D->hasAttr()) return false; if (isa(D)) return true; // Except for labels, we only care about unused decls that are local to // functions. bool WithinFunction = D->getDeclContext()->isFunctionOrMethod(); if (const auto *R = dyn_cast(D->getDeclContext())) // For dependent types, the diagnostic is deferred. WithinFunction = WithinFunction || (R->isLocalClass() && !R->isDependentType()); if (!WithinFunction) return false; if (isa(D)) return true; // White-list anything that isn't a local variable. if (!isa(D) || isa(D) || isa(D)) return false; // Types of valid local variables should be complete, so this should succeed. if (const VarDecl *VD = dyn_cast(D)) { // White-list anything with an __attribute__((unused)) type. QualType Ty = VD->getType(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs()) { if (TT->getDecl()->hasAttr()) return false; } // If we failed to complete the type for some reason, or if the type is // dependent, don't diagnose the variable. if (Ty->isIncompleteType() || Ty->isDependentType()) return false; if (const TagType *TT = Ty->getAs()) { const TagDecl *Tag = TT->getDecl(); if (Tag->hasAttr()) return false; if (const CXXRecordDecl *RD = dyn_cast(Tag)) { if (!RD->hasTrivialDestructor() && !RD->hasAttr()) return false; if (const Expr *Init = VD->getInit()) { if (const ExprWithCleanups *Cleanups = dyn_cast(Init)) Init = Cleanups->getSubExpr(); const CXXConstructExpr *Construct = dyn_cast(Init); if (Construct && !Construct->isElidable()) { CXXConstructorDecl *CD = Construct->getConstructor(); if (!CD->isTrivial() && !RD->hasAttr()) return false; } } } } // TODO: __attribute__((unused)) templates? } return true; } static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, FixItHint &Hint) { if (isa(D)) { SourceLocation AfterColon = Lexer::findLocationAfterToken(D->getLocEnd(), tok::colon, Ctx.getSourceManager(), Ctx.getLangOpts(), true); if (AfterColon.isInvalid()) return; Hint = FixItHint::CreateRemoval(CharSourceRange:: getCharRange(D->getLocStart(), AfterColon)); } return; } void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) { if (D->getTypeForDecl()->isDependentType()) return; for (auto *TmpD : D->decls()) { if (const auto *T = dyn_cast(TmpD)) DiagnoseUnusedDecl(T); else if(const auto *R = dyn_cast(TmpD)) DiagnoseUnusedNestedTypedefs(R); } } /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { if (!ShouldDiagnoseUnusedDecl(D)) return; if (auto *TD = dyn_cast(D)) { // typedefs can be referenced later on, so the diagnostics are emitted // at end-of-translation-unit. UnusedLocalTypedefNameCandidates.insert(TD); return; } FixItHint Hint; GenerateFixForUnusedDecl(D, Context, Hint); unsigned DiagID; if (isa(D) && cast(D)->isExceptionVariable()) DiagID = diag::warn_unused_exception_param; else if (isa(D)) DiagID = diag::warn_unused_label; else DiagID = diag::warn_unused_variable; Diag(D->getLocation(), DiagID) << D->getDeclName() << Hint; } static void CheckPoppedLabel(LabelDecl *L, Sema &S) { // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd // definitions are indicated with a null substmt which is also not a resolved // MS inline assembly label name. bool Diagnose = false; if (L->isMSAsmLabel()) Diagnose = !L->isResolvedMSAsmLabel(); else Diagnose = L->getStmt() == nullptr; if (Diagnose) S.Diag(L->getLocation(), diag::err_undeclared_label_use) <getDeclName(); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { S->mergeNRVOIntoParent(); if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && "Scope shouldn't contain decls!"); for (auto *TmpD : S->decls()) { assert(TmpD && "This decl didn't get pushed??"); assert(isa(TmpD) && "Decl isn't NamedDecl?"); NamedDecl *D = cast(TmpD); if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. if (!S->hasUnrecoverableErrorOccurred()) { DiagnoseUnusedDecl(D); if (const auto *RD = dyn_cast(D)) DiagnoseUnusedNestedTypedefs(RD); } // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast(D)) CheckPoppedLabel(LD, *this); // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } } /// \brief Look for an Objective-C class in the translation unit. /// /// \param Id The name of the Objective-C class we're looking for. If /// typo-correction fixes this name, the Id will be updated /// to the fixed name. /// /// \param IdLoc The location of the name in the translation unit. /// /// \param DoTypoCorrection If true, this routine will attempt typo correction /// if there is no class with the given name. /// /// \returns The declaration of the named Objective-C class, or NULL if the /// class could not be found. ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool DoTypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName); if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. if (TypoCorrection C = CorrectTypo( DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, TUScope, nullptr, llvm::make_unique>(), CTK_ErrorRecovery)) { diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id); IDecl = C.getCorrectionDeclAs(); Id = IDecl->getIdentifier(); } } ObjCInterfaceDecl *Def = dyn_cast_or_null(IDecl); // This routine must always return a class definition, if any. if (Def && Def->getDefinition()) Def = Def->getDefinition(); return Def; } /// getNonFieldDeclScope - Retrieves the innermost scope, starting /// from S, where a non-field would be declared. This routine copes /// with the difference between C and C++ scoping rules in structs and /// unions. For example, the following code is well-formed in C but /// ill-formed in C++: /// @code /// struct S6 { /// enum { BAR } e; /// }; /// /// void test_S6() { /// struct S6 a; /// a.e = BAR; /// } /// @endcode /// For the declaration of BAR, this routine will return a different /// scope. The scope S will be the scope of the unnamed enumeration /// within S6. In C++, this routine will return the scope associated /// with S6, because the enumeration's scope is a transparent /// context but structures can contain non-field names. In C, this /// routine will return the translation unit scope, since the /// enumeration's scope is a transparent context and structures cannot /// contain non-field names. Scope *Sema::getNonFieldDeclScope(Scope *S) { while (((S->getFlags() & Scope::DeclScope) == 0) || (S->getEntity() && S->getEntity()->isTransparentContext()) || (S->isClassScope() && !getLangOpts().CPlusPlus)) S = S->getParent(); return S; } /// \brief Looks up the declaration of "struct objc_super" and /// saves it for later use in building builtin declaration of /// objc_msgSendSuper and objc_msgSendSuper_stret. If no such /// pre-existing declaration exists no action takes place. static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S, IdentifierInfo *II) { if (!II->isStr("objc_msgSendSuper")) return; ASTContext &Context = ThisSema.Context; LookupResult Result(ThisSema, &Context.Idents.get("objc_super"), SourceLocation(), Sema::LookupTagName); ThisSema.LookupName(Result, S); if (Result.getResultKind() == LookupResult::Found) if (const TagDecl *TD = Result.getAsSingle()) Context.setObjCSuperType(Context.getTagDeclType(TD)); } static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) { switch (Error) { case ASTContext::GE_None: return ""; case ASTContext::GE_Missing_stdio: return "stdio.h"; case ASTContext::GE_Missing_setjmp: return "setjmp.h"; case ASTContext::GE_Missing_ucontext: return "ucontext.h"; } llvm_unreachable("unhandled error kind"); } /// LazilyCreateBuiltin - The specified Builtin-ID was first used at /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the /// built-in. NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc) { LookupPredefedObjCSuperType(*this, S, II); ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(ID, Error); if (Error) { if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_sysheader) << getHeaderName(Error) << Context.BuiltinInfo.GetName(ID); return nullptr; } if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.GetName(ID) << R; if (Context.BuiltinInfo.getHeaderName(ID) && !Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc)) Diag(Loc, diag::note_include_header_or_declare) << Context.BuiltinInfo.getHeaderName(ID) << Context.BuiltinInfo.GetName(ID); } DeclContext *Parent = Context.getTranslationUnitDecl(); if (getLangOpts().CPlusPlus) { LinkageSpecDecl *CLinkageDecl = LinkageSpecDecl::Create(Context, Parent, Loc, Loc, LinkageSpecDecl::lang_c, false); CLinkageDecl->setImplicit(); Parent->addDecl(CLinkageDecl); Parent = CLinkageDecl; } FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R, /*TInfo=*/nullptr, SC_Extern, false, /*hasPrototype=*/true); New->setImplicit(); // Create Decl objects for each parameter, adding them to the // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast(R)) { SmallVector Params; for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { ParmVarDecl *parm = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), nullptr, FT->getParamType(i), /*TInfo=*/nullptr, SC_None, nullptr); parm->setScopeInfo(0, i); Params.push_back(parm); } New->setParams(Params); } AddKnownFunctionAttributes(New); RegisterLocallyScopedExternCDecl(New, S); // TUScope is the translation-unit scope to insert this function into. // FIXME: This is hideous. We need to teach PushOnScopeChains to // relate Scopes to DeclContexts, and probably eliminate CurContext // entirely, but we're not there yet. DeclContext *SavedContext = CurContext; CurContext = Parent; PushOnScopeChains(New, TUScope); CurContext = SavedContext; return New; } /// \brief Filter out any previous declarations that the given declaration /// should not consider because they are not permitted to conflict, e.g., /// because they come from hidden sub-modules and do not refer to the same /// entity. static void filterNonConflictingPreviousDecls(ASTContext &context, NamedDecl *decl, LookupResult &previous){ // This is only interesting when modules are enabled. if (!context.getLangOpts().Modules) return; // Empty sets are uninteresting. if (previous.empty()) return; LookupResult::Filter filter = previous.makeFilter(); while (filter.hasNext()) { NamedDecl *old = filter.next(); // Non-hidden declarations are never ignored. if (!old->isHidden()) continue; if (!old->isExternallyVisible()) filter.erase(); } filter.done(); } /// Typedef declarations don't have linkage, but they still denote the same /// entity if their types are the same. /// FIXME: This is notionally doing the same thing as ASTReaderDecl's /// isSameEntity. static void filterNonConflictingPreviousTypedefDecls(ASTContext &Context, TypedefNameDecl *Decl, LookupResult &Previous) { // This is only interesting when modules are enabled. if (!Context.getLangOpts().Modules) return; // Empty sets are uninteresting. if (Previous.empty()) return; LookupResult::Filter Filter = Previous.makeFilter(); while (Filter.hasNext()) { NamedDecl *Old = Filter.next(); // Non-hidden declarations are never ignored. if (!Old->isHidden()) continue; // Declarations of the same entity are not ignored, even if they have // different linkages. if (auto *OldTD = dyn_cast(Old)) if (Context.hasSameType(OldTD->getUnderlyingType(), Decl->getUnderlyingType())) continue; if (!Old->isExternallyVisible()) Filter.erase(); } Filter.done(); } bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { QualType OldType; if (TypedefNameDecl *OldTypedef = dyn_cast(Old)) OldType = OldTypedef->getUnderlyingType(); else OldType = Context.getTypeDeclType(Old); QualType NewType = New->getUnderlyingType(); if (NewType->isVariablyModifiedType()) { // Must not redefine a typedef with a variably-modified type. int Kind = isa(Old) ? 1 : 0; Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef) << Kind << NewType; if (Old->getLocation().isValid()) Diag(Old->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return true; } if (OldType != NewType && !OldType->isDependentType() && !NewType->isDependentType() && !Context.hasSameType(OldType, NewType)) { int Kind = isa(Old) ? 1 : 0; Diag(New->getLocation(), diag::err_redefinition_different_typedef) << Kind << NewType << OldType; if (Old->getLocation().isValid()) Diag(Old->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return true; } return false; } /// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the /// same name and scope as a previous declaration 'Old'. Figure out /// how to resolve this situation, merging decls or emitting /// diagnostics as appropriate. If there was an error, set New to be invalid. /// void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { // If the new decl is known invalid already, don't bother doing any // merging checks. if (New->isInvalidDecl()) return; // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! if (getLangOpts().ObjC1) { const IdentifierInfo *TypeID = New->getIdentifier(); switch (TypeID->getLength()) { default: break; case 2: { if (!TypeID->isStr("id")) break; QualType T = New->getUnderlyingType(); if (!T->isPointerType()) break; if (!T->isVoidPointerType()) { QualType PT = T->getAs()->getPointeeType(); if (!PT->isStructureType()) break; } Context.setObjCIdRedefinitionType(T); // Install the built-in type for 'id', ignoring the current definition. New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); return; } case 5: if (!TypeID->isStr("Class")) break; Context.setObjCClassRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'Class', ignoring the current definition. New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) break; Context.setObjCSelRedefinitionType(New->getUnderlyingType()); // Install the built-in type for 'SEL', ignoring the current definition. New->setTypeForDecl(Context.getObjCSelType().getTypePtr()); return; } // Fall through - the typedef name was not a builtin type. } // Verify the old decl was also a type. TypeDecl *Old = OldDecls.getAsSingle(); if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); NamedDecl *OldD = OldDecls.getRepresentativeDecl(); if (OldD->getLocation().isValid()) Diag(OldD->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } // If the old declaration is invalid, just give up here. if (Old->isInvalidDecl()) return New->setInvalidDecl(); // If the typedef types are not identical, reject them in all languages and // with any extensions enabled. if (isIncompatibleTypedef(Old, New)) return; // The types match. Link up the redeclaration chain and merge attributes if // the old declaration was a typedef. if (TypedefNameDecl *Typedef = dyn_cast(Old)) { New->setPreviousDecl(Typedef); mergeDeclAttributes(New, Old); } if (getLangOpts().MicrosoftExt) return; if (getLangOpts().CPlusPlus) { // C++ [dcl.typedef]p2: // In a given non-class scope, a typedef specifier can be used to // redefine the name of any type declared in that scope to refer // to the type to which it already refers. if (!isa(CurContext)) return; // C++0x [dcl.typedef]p4: // In a given class scope, a typedef specifier can be used to redefine // any class-name declared in that scope that is not also a typedef-name // to refer to the type to which it already refers. // // This wording came in via DR424, which was a correction to the // wording in DR56, which accidentally banned code like: // // struct S { // typedef struct A { } A; // }; // // in the C++03 standard. We implement the C++0x semantics, which // allow the above but disallow // // struct S { // typedef int I; // typedef int I; // }; // // since that was the intent of DR56. if (!isa(Old)) return; Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } // Modules always permit redefinition of typedefs, as does C11. if (getLangOpts().Modules || getLangOpts().C11) return; // If we have a redefinition of a typedef in C, emit a warning. This warning // is normally mapped to an error, but can be controlled with // -Wtypedef-redefinition. If either the original or the redefinition is // in a system header, don't emit this for compatibility with GCC. if (getDiagnostics().getSuppressSystemWarnings() && (Context.getSourceManager().isInSystemHeader(Old->getLocation()) || Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; Diag(New->getLocation(), diag::ext_redefinition_of_typedef) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return; } /// DeclhasAttr - returns true if decl Declaration already has the target /// attribute. static bool DeclHasAttr(const Decl *D, const Attr *A) { const OwnershipAttr *OA = dyn_cast(A); const AnnotateAttr *Ann = dyn_cast(A); for (const auto *i : D->attrs()) if (i->getKind() == A->getKind()) { if (Ann) { if (Ann->getAnnotation() == cast(i)->getAnnotation()) return true; continue; } // FIXME: Don't hardcode this check if (OA && isa(i)) return OA->getOwnKind() == cast(i)->getOwnKind(); return true; } return false; } static bool isAttributeTargetADefinition(Decl *D) { if (VarDecl *VD = dyn_cast(D)) return VD->isThisDeclarationADefinition(); if (TagDecl *TD = dyn_cast(D)) return TD->isCompleteDefinition() || TD->isBeingDefined(); return true; } /// Merge alignment attributes from \p Old to \p New, taking into account the /// special semantics of C11's _Alignas specifier and C++11's alignas attribute. /// /// \return \c true if any attributes were added to \p New. static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) { // Look for alignas attributes on Old, and pick out whichever attribute // specifies the strictest alignment requirement. AlignedAttr *OldAlignasAttr = nullptr; AlignedAttr *OldStrictestAlignAttr = nullptr; unsigned OldAlign = 0; for (auto *I : Old->specific_attrs()) { // FIXME: We have no way of representing inherited dependent alignments // in a case like: // template struct alignas(A) X; // template struct alignas(B) X {}; // For now, we just ignore any alignas attributes which are not on the // definition in such a case. if (I->isAlignmentDependent()) return false; if (I->isAlignas()) OldAlignasAttr = I; unsigned Align = I->getAlignment(S.Context); if (Align > OldAlign) { OldAlign = Align; OldStrictestAlignAttr = I; } } // Look for alignas attributes on New. AlignedAttr *NewAlignasAttr = nullptr; unsigned NewAlign = 0; for (auto *I : New->specific_attrs()) { if (I->isAlignmentDependent()) return false; if (I->isAlignas()) NewAlignasAttr = I; unsigned Align = I->getAlignment(S.Context); if (Align > NewAlign) NewAlign = Align; } if (OldAlignasAttr && NewAlignasAttr && OldAlign != NewAlign) { // Both declarations have 'alignas' attributes. We require them to match. // C++11 [dcl.align]p6 and C11 6.7.5/7 both come close to saying this, but // fall short. (If two declarations both have alignas, they must both match // every definition, and so must match each other if there is a definition.) // If either declaration only contains 'alignas(0)' specifiers, then it // specifies the natural alignment for the type. if (OldAlign == 0 || NewAlign == 0) { QualType Ty; if (ValueDecl *VD = dyn_cast(New)) Ty = VD->getType(); else Ty = S.Context.getTagDeclType(cast(New)); if (OldAlign == 0) OldAlign = S.Context.getTypeAlign(Ty); if (NewAlign == 0) NewAlign = S.Context.getTypeAlign(Ty); } if (OldAlign != NewAlign) { S.Diag(NewAlignasAttr->getLocation(), diag::err_alignas_mismatch) << (unsigned)S.Context.toCharUnitsFromBits(OldAlign).getQuantity() << (unsigned)S.Context.toCharUnitsFromBits(NewAlign).getQuantity(); S.Diag(OldAlignasAttr->getLocation(), diag::note_previous_declaration); } } if (OldAlignasAttr && !NewAlignasAttr && isAttributeTargetADefinition(New)) { // C++11 [dcl.align]p6: // if any declaration of an entity has an alignment-specifier, // every defining declaration of that entity shall specify an // equivalent alignment. // C11 6.7.5/7: // If the definition of an object does not have an alignment // specifier, any other declaration of that object shall also // have no alignment specifier. S.Diag(New->getLocation(), diag::err_alignas_missing_on_definition) << OldAlignasAttr; S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration) << OldAlignasAttr; } bool AnyAdded = false; // Ensure we have an attribute representing the strictest alignment. if (OldAlign > NewAlign) { AlignedAttr *Clone = OldStrictestAlignAttr->clone(S.Context); Clone->setInherited(true); New->addAttr(Clone); AnyAdded = true; } // Ensure we have an alignas attribute if the old declaration had one. if (OldAlignasAttr && !NewAlignasAttr && !(AnyAdded && OldStrictestAlignAttr->isAlignas())) { AlignedAttr *Clone = OldAlignasAttr->clone(S.Context); Clone->setInherited(true); New->addAttr(Clone); AnyAdded = true; } return AnyAdded; } static bool mergeDeclAttribute(Sema &S, NamedDecl *D, const InheritableAttr *Attr, bool Override) { InheritableAttr *NewAttr = nullptr; unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast(Attr)) NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(), AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), AA->getMessage(), Override, AttrSpellingListIndex); else if (const auto *VA = dyn_cast(Attr)) NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); else if (const auto *VA = dyn_cast(Attr)) NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), AttrSpellingListIndex); else if (const auto *ImportA = dyn_cast(Attr)) NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(), AttrSpellingListIndex); else if (const auto *ExportA = dyn_cast(Attr)) NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(), AttrSpellingListIndex); else if (const auto *FA = dyn_cast(Attr)) NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(), FA->getFormatIdx(), FA->getFirstArg(), AttrSpellingListIndex); else if (const auto *SA = dyn_cast(Attr)) NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(), AttrSpellingListIndex); else if (const auto *IA = dyn_cast(Attr)) NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(), AttrSpellingListIndex, IA->getSemanticSpelling()); else if (const auto *AA = dyn_cast(Attr)) NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), &S.Context.Idents.get(AA->getSpelling()), AttrSpellingListIndex); else if (const auto *MA = dyn_cast(Attr)) NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); else if (const auto *OA = dyn_cast(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); else if (isa(Attr)) // AlignedAttrs are handled separately, because we need to handle all // such attributes on a declaration at the same time. NewAttr = nullptr; else if (isa(Attr) && Override) NewAttr = nullptr; else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr)) NewAttr = cast(Attr->clone(S.Context)); if (NewAttr) { NewAttr->setInherited(true); D->addAttr(NewAttr); return true; } return false; } static const Decl *getDefinition(const Decl *D) { if (const TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *Def = VD->getDefinition(); if (Def) return Def; return VD->getActingDefinition(); } if (const FunctionDecl *FD = dyn_cast(D)) { const FunctionDecl* Def; if (FD->isDefined(Def)) return Def; } return nullptr; } static bool hasAttribute(const Decl *D, attr::Kind Kind) { for (const auto *Attribute : D->attrs()) if (Attribute->getKind() == Kind) return true; return false; } /// checkNewAttributesAfterDef - If we already have a definition, check that /// there are no new attributes in this declaration. static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { if (!New->hasAttrs()) return; const Decl *Def = getDefinition(Old); if (!Def || Def == New) return; AttrVec &NewAttributes = New->getAttrs(); for (unsigned I = 0, E = NewAttributes.size(); I != E;) { const Attr *NewAttribute = NewAttributes[I]; if (isa(NewAttribute)) { if (FunctionDecl *FD = dyn_cast(New)) S.CheckForFunctionRedefinition(FD, cast(Def)); else { VarDecl *VD = cast(New); unsigned Diag = cast(Def)->isThisDeclarationADefinition() == VarDecl::TentativeDefinition ? diag::err_alias_after_tentative : diag::err_redefinition; S.Diag(VD->getLocation(), Diag) << VD->getDeclName(); S.Diag(Def->getLocation(), diag::note_previous_definition); VD->setInvalidDecl(); } ++I; continue; } if (const VarDecl *VD = dyn_cast(Def)) { // Tentative definitions are only interesting for the alias check above. if (VD->isThisDeclarationADefinition() != VarDecl::Definition) { ++I; continue; } } if (hasAttribute(Def, NewAttribute->getKind())) { ++I; continue; // regular attr merging will take care of validating this. } if (isa(NewAttribute)) { // C's _Noreturn is allowed to be added to a function after it is defined. ++I; continue; } else if (const AlignedAttr *AA = dyn_cast(NewAttribute)) { if (AA->isAlignas()) { // C++11 [dcl.align]p6: // if any declaration of an entity has an alignment-specifier, // every defining declaration of that entity shall specify an // equivalent alignment. // C11 6.7.5/7: // If the definition of an object does not have an alignment // specifier, any other declaration of that object shall also // have no alignment specifier. S.Diag(Def->getLocation(), diag::err_alignas_missing_on_definition) << AA; S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration) << AA; NewAttributes.erase(NewAttributes.begin() + I); --E; continue; } } S.Diag(NewAttribute->getLocation(), diag::warn_attribute_precede_definition); S.Diag(Def->getLocation(), diag::note_previous_definition); NewAttributes.erase(NewAttributes.begin() + I); --E; } } /// mergeDeclAttributes - Copy attributes from the Old decl to the New one. void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK) { if (UsedAttr *OldAttr = Old->getMostRecentDecl()->getAttr()) { UsedAttr *NewAttr = OldAttr->clone(Context); NewAttr->setInherited(true); New->addAttr(NewAttr); } if (!Old->hasAttrs() && !New->hasAttrs()) return; // attributes declared post-definition are currently ignored checkNewAttributesAfterDef(*this, New, Old); if (!Old->hasAttrs()) return; bool foundAny = New->hasAttrs(); // Ensure that any moving of objects within the allocated map is done before // we process them. if (!foundAny) New->setAttrs(AttrVec()); for (auto *I : Old->specific_attrs()) { bool Override = false; // Ignore deprecated/unavailable/availability attributes if requested. if (isa(I) || isa(I) || isa(I)) { switch (AMK) { case AMK_None: continue; case AMK_Redeclaration: break; case AMK_Override: Override = true; break; } } // Already handled. if (isa(I)) continue; if (mergeDeclAttribute(*this, New, I, Override)) foundAny = true; } if (mergeAlignedAttrs(*this, New, Old)) foundAny = true; if (!foundAny) New->dropAttrs(); } /// mergeParamDeclAttributes - Copy attributes from the old parameter /// to the new one. static void mergeParamDeclAttributes(ParmVarDecl *newDecl, const ParmVarDecl *oldDecl, Sema &S) { // C++11 [dcl.attr.depend]p2: // The first declaration of a function shall specify the // carries_dependency attribute for its declarator-id if any declaration // of the function specifies the carries_dependency attribute. const CarriesDependencyAttr *CDA = newDecl->getAttr(); if (CDA && !oldDecl->hasAttr()) { S.Diag(CDA->getLocation(), diag::err_carries_dependency_missing_on_first_decl) << 1/*Param*/; // Find the first declaration of the parameter. // FIXME: Should we build redeclaration chains for function parameters? const FunctionDecl *FirstFD = cast(oldDecl->getDeclContext())->getFirstDecl(); const ParmVarDecl *FirstVD = FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex()); S.Diag(FirstVD->getLocation(), diag::note_carries_dependency_missing_first_decl) << 1/*Param*/; } if (!oldDecl->hasAttrs()) return; bool foundAny = newDecl->hasAttrs(); // Ensure that any moving of objects within the allocated map is // done before we process them. if (!foundAny) newDecl->setAttrs(AttrVec()); for (const auto *I : oldDecl->specific_attrs()) { if (!DeclHasAttr(newDecl, I)) { InheritableAttr *newAttr = cast(I->clone(S.Context)); newAttr->setInherited(true); newDecl->addAttr(newAttr); foundAny = true; } } if (!foundAny) newDecl->dropAttrs(); } namespace { /// Used in MergeFunctionDecl to keep track of function parameters in /// C. struct GNUCompatibleParamWarning { ParmVarDecl *OldParm; ParmVarDecl *NewParm; QualType PromotedType; }; } /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { if (Ctor->isDefaultConstructor()) return Sema::CXXDefaultConstructor; if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; if (Ctor->isMoveConstructor()) return Sema::CXXMoveConstructor; } else if (isa(MD)) { return Sema::CXXDestructor; } else if (MD->isCopyAssignmentOperator()) { return Sema::CXXCopyAssignment; } else if (MD->isMoveAssignmentOperator()) { return Sema::CXXMoveAssignment; } return Sema::CXXInvalid; } // Determine whether the previous declaration was a definition, implicit // declaration, or a declaration. template static std::pair getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) { diag::kind PrevDiag; SourceLocation OldLocation = Old->getLocation(); if (Old->isThisDeclarationADefinition()) PrevDiag = diag::note_previous_definition; else if (Old->isImplicit()) { PrevDiag = diag::note_previous_implicit_declaration; if (OldLocation.isInvalid()) OldLocation = New->getLocation(); } else PrevDiag = diag::note_previous_declaration; return std::make_pair(PrevDiag, OldLocation); } /// canRedefineFunction - checks if a function can be redefined. Currently, /// only extern inline functions can be redefined, and even then only in /// GNU89 mode. static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { return ((FD->hasAttr() || LangOpts.GNUInline) && !LangOpts.CPlusPlus && FD->isInlineSpecified() && FD->getStorageClass() == SC_Extern); } const AttributedType *Sema::getCallingConvAttributedType(QualType T) const { const AttributedType *AT = T->getAs(); while (AT && !AT->isCallingConv()) AT = AT->getModifiedType()->getAs(); return AT; } template static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { const DeclContext *DC = Old->getDeclContext(); if (DC->isRecord()) return false; LanguageLinkage OldLinkage = Old->getLanguageLinkage(); if (OldLinkage == CXXLanguageLinkage && New->isInExternCContext()) return true; if (OldLinkage == CLanguageLinkage && New->isInExternCXXContext()) return true; return false; } /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, /// merging decls or emitting diagnostics as appropriate. /// /// In C++, New and Old must be declarations that are not /// overloaded. Use IsOverload to determine whether New and Old are /// overloaded, and to select the Old declaration that New should be /// merged with. /// /// Returns true if there was an error, false otherwise. bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, bool MergeTypeWithOld) { // Verify the old decl was also a function. FunctionDecl *Old = OldD->getAsFunction(); if (!Old) { if (UsingShadowDecl *Shadow = dyn_cast(OldD)) { if (New->getFriendObjectKind()) { Diag(New->getLocation(), diag::err_using_decl_friend); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; return true; } // C++11 [namespace.udecl]p14: // If a function declaration in namespace scope or block scope has the // same name and the same parameter-type-list as a function introduced // by a using-declaration, and the declarations do not declare the same // function, the program is ill-formed. // Check whether the two declarations might declare the same function. Old = dyn_cast(Shadow->getTargetDecl()); if (Old && !Old->getDeclContext()->getRedeclContext()->Equals( New->getDeclContext()->getRedeclContext()) && !(Old->isExternC() && New->isExternC())) Old = nullptr; if (!Old) { Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); Diag(Shadow->getTargetDecl()->getLocation(), diag::note_using_decl_target); Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; return true; } OldD = Old; } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(OldD->getLocation(), diag::note_previous_definition); return true; } } // If the old declaration is invalid, just give up here. if (Old->isInvalidDecl()) return true; diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. // Don't complain about specializations. They are not supposed to have // storage classes. if (!isa(New) && !isa(Old) && New->getStorageClass() == SC_Static && Old->hasExternalFormalLinkage() && !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::ext_static_non_static) << New; Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New; Diag(OldLocation, PrevDiag); return true; } } // If a function is first declared with a calling convention, but is later // declared or defined without one, all following decls assume the calling // convention of the first. // // It's OK if a function is first declared without a calling convention, // but is later declared or defined with the default calling convention. // // To test if either decl has an explicit calling convention, we look for // AttributedType sugar nodes on the type as written. If they are missing or // were canonicalized away, we assume the calling convention was implicit. // // Note also that we DO NOT return at this point, because we still have // other tests to run. QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); const FunctionType *OldType = cast(OldQType); const FunctionType *NewType = cast(NewQType); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) { FunctionDecl *First = Old->getFirstDecl(); const FunctionType *FT = First->getType().getCanonicalType()->castAs(); FunctionType::ExtInfo FI = FT->getExtInfo(); bool NewCCExplicit = getCallingConvAttributedType(New->getType()); if (!NewCCExplicit) { // Inherit the CC from the previous declaration if it was specified // there but not here. NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; } else { // Calling conventions aren't compatible, so complain. bool FirstCCExplicit = getCallingConvAttributedType(First->getType()); Diag(New->getLocation(), diag::err_cconv_change) << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) << !FirstCCExplicit << (!FirstCCExplicit ? "" : FunctionType::getNameForCallConv(FI.getCC())); // Put the note on the first decl, since it is the one that matters. Diag(First->getLocation(), diag::note_previous_declaration); return true; } } // FIXME: diagnose the other way around? if (OldTypeInfo.getNoReturn() && !NewTypeInfo.getNoReturn()) { NewTypeInfo = NewTypeInfo.withNoReturn(true); RequiresAdjustment = true; } // Merge regparm attribute. if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() || OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { if (NewTypeInfo.getHasRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); Diag(OldLocation, diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withRegParm(OldTypeInfo.getRegParm()); RequiresAdjustment = true; } // Merge ns_returns_retained attribute. if (OldTypeInfo.getProducesResult() != NewTypeInfo.getProducesResult()) { if (NewTypeInfo.getProducesResult()) { Diag(New->getLocation(), diag::err_returns_retained_mismatch); Diag(OldLocation, diag::note_previous_declaration); return true; } NewTypeInfo = NewTypeInfo.withProducesResult(true); RequiresAdjustment = true; } if (RequiresAdjustment) { const FunctionType *AdjustedType = New->getType()->getAs(); AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo); New->setType(QualType(AdjustedType, 0)); NewQType = Context.getCanonicalType(New->getType()); NewType = cast(NewQType); } // If this redeclaration makes the function inline, we may need to add it to // UndefinedButUsed. if (!Old->isInlined() && New->isInlined() && !New->hasAttr() && (getLangOpts().CPlusPlus || !getLangOpts().GNUInline) && Old->isUsed(false) && !Old->isDefined() && !New->isThisDeclarationADefinition()) UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(), SourceLocation())); // If this redeclaration makes it newly gnu_inline, we don't want to warn // about it. if (New->hasAttr() && Old->isInlined() && !Old->hasAttr()) { UndefinedButUsed.erase(Old->getCanonicalDecl()); } if (getLangOpts().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. // Go back to the type source info to compare the declared return types, // per C++1y [dcl.type.auto]p13: // Redeclarations or specializations of a function or function template // with a declared return type that uses a placeholder type shall also // use that placeholder, not a deduced type. QualType OldDeclaredReturnType = (Old->getTypeSourceInfo() ? Old->getTypeSourceInfo()->getType()->castAs() : OldType)->getReturnType(); QualType NewDeclaredReturnType = (New->getTypeSourceInfo() ? New->getTypeSourceInfo()->getType()->castAs() : NewType)->getReturnType(); QualType ResQT; if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) && !((NewQType->isDependentType() || OldQType->isDependentType()) && New->isLocalExternDecl())) { if (NewDeclaredReturnType->isObjCObjectPointerType() && OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { if (New->isCXXClassMember() && New->isOutOfLine()) Diag(New->getLocation(), diag::err_member_def_does_not_match_ret_type) << New << New->getReturnTypeSourceRange(); else Diag(New->getLocation(), diag::err_ovl_diff_return_type) << New->getReturnTypeSourceRange(); Diag(OldLocation, PrevDiag) << Old << Old->getType() << Old->getReturnTypeSourceRange(); return true; } else NewQType = ResQT; } QualType OldReturnType = OldType->getReturnType(); QualType NewReturnType = cast(NewQType)->getReturnType(); if (OldReturnType != NewReturnType) { // If this function has a deduced return type and has already been // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { New->setType( SubstAutoType(New->getType(), OldAT->isDependentType() ? Context.DependentTy : OldAT->getDeducedType())); NewQType = Context.getCanonicalType( SubstAutoType(NewQType, OldAT->isDependentType() ? Context.DependentTy : OldAT->getDeducedType())); } } const CXXMethodDecl *OldMethod = dyn_cast(Old); CXXMethodDecl *NewMethod = dyn_cast(New); if (OldMethod && NewMethod) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); // MSVC allows explicit template specialization at class scope: // 2 CXXMethodDecls referring to the same function will be injected. // We don't want a redeclaration error. bool IsClassScopeExplicitSpecialization = OldMethod->isFunctionTemplateSpecialization() && NewMethod->isFunctionTemplateSpecialization(); bool isFriend = NewMethod->getFriendObjectKind(); if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() && !IsClassScopeExplicitSpecialization) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. if (OldMethod->isStatic() != NewMethod->isStatic()) { Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } // C++ [class.mem]p1: // [...] A member shall not be declared twice in the // member-specification, except that a nested class or member // class template can be declared and then later defined. if (ActiveTemplateInstantiations.empty()) { unsigned NewDiag; if (isa(OldMethod)) NewDiag = diag::err_constructor_redeclared; else if (isa(NewMethod)) NewDiag = diag::err_destructor_redeclared; else if (isa(NewMethod)) NewDiag = diag::err_conv_function_redeclared; else NewDiag = diag::err_member_redeclared; Diag(New->getLocation(), NewDiag); } else { Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation) << New << New->getType(); } Diag(OldLocation, PrevDiag) << Old << Old->getType(); // Complain if this is an explicit declaration of a special // member that was initially declared implicitly. // // As an exception, it's okay to befriend such methods in order // to permit the implicit constructor/destructor/operator calls. } else if (OldMethod->isImplicit()) { if (isFriend) { NewMethod->setImplicit(); } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) << New << getSpecialMember(OldMethod); return true; } } else if (OldMethod->isExplicitlyDefaulted() && !isFriend) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) << getSpecialMember(OldMethod); return true; } } // C++11 [dcl.attr.noreturn]p1: // The first declaration of a function shall specify the noreturn // attribute if any declaration of that function specifies the noreturn // attribute. const CXX11NoReturnAttr *NRA = New->getAttr(); if (NRA && !Old->hasAttr()) { Diag(NRA->getLocation(), diag::err_noreturn_missing_on_first_decl); Diag(Old->getFirstDecl()->getLocation(), diag::note_noreturn_missing_first_decl); } // C++11 [dcl.attr.depend]p2: // The first declaration of a function shall specify the // carries_dependency attribute for its declarator-id if any declaration // of the function specifies the carries_dependency attribute. const CarriesDependencyAttr *CDA = New->getAttr(); if (CDA && !Old->hasAttr()) { Diag(CDA->getLocation(), diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/; Diag(Old->getFirstDecl()->getLocation(), diag::note_carries_dependency_missing_first_decl) << 0/*Function*/; } // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. // We also want to respect all the extended bits except noreturn. // noreturn should now match unless the old type info didn't have it. QualType OldQTypeForComparison = OldQType; if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { assert(OldQType == QualType(OldType, 0)); const FunctionType *OldTypeForComparison = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); OldQTypeForComparison = QualType(OldTypeForComparison, 0); assert(OldQTypeForComparison.isCanonical()); } if (haveIncompatibleLanguageLinkages(Old, New)) { // As a special case, retain the language linkage from previous // declarations of a friend function as an extension. // // This liberal interpretation of C++ [class.friend]p3 matches GCC/MSVC // and is useful because there's otherwise no way to specify language // linkage within class scope. // // Check cautiously as the friend object kind isn't yet complete. if (New->getFriendObjectKind() != Decl::FOK_None) { Diag(New->getLocation(), diag::ext_retained_language_linkage) << New; Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(OldLocation, PrevDiag); return true; } } if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); if ((NewQType->isDependentType() || OldQType->isDependentType()) && New->isLocalExternDecl()) { // It's OK if we couldn't merge types for a local function declaraton // if either the old or new type is dependent. We'll merge the types // when we instantiate the function. return false; } // Fall through for conflicting redeclarations and redefinitions. } // C: Function types need to be compatible, not identical. This handles // duplicate function decls like "void f(int); void f(enum X);" properly. if (!getLangOpts().CPlusPlus && Context.typesAreCompatible(OldQType, NewQType)) { const FunctionType *OldFuncType = OldQType->getAs(); const FunctionType *NewFuncType = NewQType->getAs(); const FunctionProtoType *OldProto = nullptr; if (MergeTypeWithOld && isa(NewFuncType) && (OldProto = dyn_cast(OldFuncType))) { // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); SmallVector ParamTypes(OldProto->param_types()); NewQType = Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); // Synthesize parameters with the same types. SmallVector Params; for (const auto &ParamType : OldProto->param_types()) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), SourceLocation(), nullptr, ParamType, /*TInfo=*/nullptr, SC_None, nullptr); Param->setScopeInfo(0, Params.size()); Param->setImplicit(); Params.push_back(Param); } New->setParams(Params); } return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); } // GNU C permits a K&R definition to follow a prototype declaration // if the declared types of the parameters in the K&R definition // match the types in the prototype declaration, even when the // promoted types of the parameters from the K&R definition differ // from the types in the prototype. GCC then keeps the types from // the prototype. // // If a variadic prototype is followed by a non-variadic K&R definition, // the K&R definition becomes variadic. This is sort of an edge case, but // it's legal per the standard depending on how you read C99 6.7.5.3p15 and // C99 6.9.1p8. if (!getLangOpts().CPlusPlus && Old->hasPrototype() && !New->hasPrototype() && New->getType()->getAs() && Old->getNumParams() == New->getNumParams()) { SmallVector ArgTypes; SmallVector Warnings; const FunctionProtoType *OldProto = Old->getType()->getAs(); const FunctionProtoType *NewProto = New->getType()->getAs(); // Determine whether this is the GNU C extension. QualType MergedReturn = Context.mergeTypes(OldProto->getReturnType(), NewProto->getReturnType()); bool LooseCompatible = !MergedReturn.isNull(); for (unsigned Idx = 0, End = Old->getNumParams(); LooseCompatible && Idx != End; ++Idx) { ParmVarDecl *OldParm = Old->getParamDecl(Idx); ParmVarDecl *NewParm = New->getParamDecl(Idx); if (Context.typesAreCompatible(OldParm->getType(), NewProto->getParamType(Idx))) { ArgTypes.push_back(NewParm->getType()); } else if (Context.typesAreCompatible(OldParm->getType(), NewParm->getType(), /*CompareUnqualified=*/true)) { GNUCompatibleParamWarning Warn = { OldParm, NewParm, NewProto->getParamType(Idx) }; Warnings.push_back(Warn); ArgTypes.push_back(NewParm->getType()); } else LooseCompatible = false; } if (LooseCompatible) { for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) { Diag(Warnings[Warn].NewParm->getLocation(), diag::ext_param_promoted_not_compatible_with_prototype) << Warnings[Warn].PromotedType << Warnings[Warn].OldParm->getType(); if (Warnings[Warn].OldParm->getLocation().isValid()) Diag(Warnings[Warn].OldParm->getLocation(), diag::note_previous_declaration); } if (MergeTypeWithOld) New->setType(Context.getFunctionType(MergedReturn, ArgTypes, OldProto->getExtProtoInfo())); return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); } // Fall through to diagnose conflicting types. } // A function that has already been declared has been redeclared or // defined with a different type; show an appropriate diagnostic. // If the previous declaration was an implicitly-generated builtin // declaration, then at the very least we should use a specialized note. unsigned BuiltinID; if (Old->isImplicit() && (BuiltinID = Old->getBuiltinID())) { // If it's actually a library-defined builtin function like 'malloc' // or 'printf', just warn about the incompatible redeclaration. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; Diag(OldLocation, diag::note_previous_builtin_declaration) << Old << Old->getType(); // If this is a global redeclaration, just forget hereafter // about the "builtin-ness" of the function. // // Doing this for local extern declarations is problematic. If // the builtin declaration remains visible, a second invalid // local declaration will produce a hard error; if it doesn't // remain visible, a single bogus local redeclaration (which is // actually only a warning) could break all the downstream code. if (!New->getLexicalDeclContext()->isFunctionOrMethod()) New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); return false; } PrevDiag = diag::note_previous_builtin_declaration; } Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName(); Diag(OldLocation, PrevDiag) << Old << Old->getType(); return true; } /// \brief Completes the merge of two function declarations that are /// known to be compatible. /// /// This routine handles the merging of attributes and other /// properties of function declarations from the old declaration to /// the new declaration, once we know that New is in fact a /// redeclaration of Old. /// /// \returns false bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld) { // Merge the attributes mergeDeclAttributes(New, Old); // Merge "pure" flag. if (Old->isPure()) New->setPure(); // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) New->setIsUsed(); // Merge attributes from the parameters. These can mismatch with K&R // declarations. if (New->getNumParams() == Old->getNumParams()) for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i), *this); if (getLangOpts().CPlusPlus) return MergeCXXFunctionDecl(New, Old, S); // Merge the function types so the we get the composite types for the return // and argument types. Per C11 6.2.7/4, only update the type if the old decl // was visible. QualType Merged = Context.mergeTypes(Old->getType(), New->getType()); if (!Merged.isNull() && MergeTypeWithOld) New->setType(Merged); return false; } void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { // Merge the attributes, including deprecated/unavailable AvailabilityMergeKind MergeKind = isa(newMethod->getDeclContext()) ? AMK_Redeclaration : AMK_Override; mergeDeclAttributes(newMethod, oldMethod, MergeKind); // Merge attributes from the parameters. ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(), oe = oldMethod->param_end(); for (ObjCMethodDecl::param_iterator ni = newMethod->param_begin(), ne = newMethod->param_end(); ni != ne && oi != oe; ++ni, ++oi) mergeParamDeclAttributes(*ni, *oi, *this); CheckObjCMethodOverride(newMethod, oldMethod); } /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and /// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. /// /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back /// to here in AddInitializerToDecl. We can't check them before the initializer /// is attached. void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld) { if (New->isInvalidDecl() || Old->isInvalidDecl()) return; QualType MergedT; if (getLangOpts().CPlusPlus) { if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { // These could still be something that needs exception specs checked. return MergeVarDeclExceptionSpecs(New, Old); } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an // array object can specify array types that differ by the presence or // absence of a major array bound (8.3.4). else if (Old->getType()->isIncompleteArrayType() && New->getType()->isArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); if (Context.hasSameType(OldArray->getElementType(), NewArray->getElementType())) MergedT = New->getType(); } else if (Old->getType()->isArrayType() && New->getType()->isIncompleteArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); if (Context.hasSameType(OldArray->getElementType(), NewArray->getElementType())) MergedT = Old->getType(); } else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); } } else { // C 6.2.7p2: // All declarations that refer to the same object or function shall have // compatible type. MergedT = Context.mergeTypes(New->getType(), Old->getType()); } if (MergedT.isNull()) { // It's OK if we couldn't merge types if either type is dependent, for a // block-scope variable. In other cases (static data members of class // templates, variable templates, ...), we require the types to be // equivalent. // FIXME: The C++ standard doesn't say anything about this. if ((New->getType()->isDependentType() || Old->getType()->isDependentType()) && New->isLocalVarDecl()) { // If the old type was dependent, we can't merge with it, so the new type // becomes dependent for now. We'll reproduce the original type when we // instantiate the TypeSourceInfo for the variable. if (!New->getType()->isDependentType() && MergeTypeWithOld) New->setType(Context.DependentTy); return; } // FIXME: Even if this merging succeeds, some other non-visible declaration // of this variable might have an incompatible type. For instance: // // extern int arr[]; // void f() { extern int arr[2]; } // void g() { extern int arr[3]; } // // Neither C nor C++ requires a diagnostic for this, but we should still try // to diagnose it. Diag(New->getLocation(), diag::err_redefinition_different_type) << New->getDeclName() << New->getType() << Old->getType(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } // Don't actually update the type on the new declaration if the old // declaration was an extern declaration in a different scope. if (MergeTypeWithOld) New->setType(MergedT); } static bool mergeTypeWithPrevious(Sema &S, VarDecl *NewVD, VarDecl *OldVD, LookupResult &Previous) { // C11 6.2.7p4: // For an identifier with internal or external linkage declared // in a scope in which a prior declaration of that identifier is // visible, if the prior declaration specifies internal or // external linkage, the type of the identifier at the later // declaration becomes the composite type. // // If the variable isn't visible, we do not merge with its type. if (Previous.isShadowed()) return false; if (S.getLangOpts().CPlusPlus) { // C++11 [dcl.array]p3: // If there is a preceding declaration of the entity in the same // scope in which the bound was specified, an omitted array bound // is taken to be the same as in that earlier declaration. return NewVD->isPreviousDeclInSameBlockScope() || (!OldVD->getLexicalDeclContext()->isFunctionOrMethod() && !NewVD->getLexicalDeclContext()->isFunctionOrMethod()); } else { // If the old declaration was function-local, don't merge with its // type unless we're in the same function. return !OldVD->getLexicalDeclContext()->isFunctionOrMethod() || OldVD->getLexicalDeclContext() == NewVD->getLexicalDeclContext(); } } /// MergeVarDecl - We just parsed a variable 'New' which has the same name /// and scope as a previous declaration 'Old'. Figure out how to resolve this /// situation, merging decls or emitting diagnostics as appropriate. /// /// Tentative definition rules (C99 6.9.2p2) are checked by /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. /// void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // If the new decl is already invalid, don't do any other checking. if (New->isInvalidDecl()) return; VarTemplateDecl *NewTemplate = New->getDescribedVarTemplate(); // Verify the old decl was also a variable or variable template. VarDecl *Old = nullptr; VarTemplateDecl *OldTemplate = nullptr; if (Previous.isSingleResult()) { if (NewTemplate) { OldTemplate = dyn_cast(Previous.getFoundDecl()); Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr; } else Old = dyn_cast(Previous.getFoundDecl()); } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(Previous.getRepresentativeDecl()->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } if (!shouldLinkPossiblyHiddenDecl(Old, New)) return; // Ensure the template parameters are compatible. if (NewTemplate && !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), OldTemplate->getTemplateParameters(), /*Complain=*/true, TPL_TemplateMatch)) return; // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] // // Here, we need only consider static data members. if (Old->isStaticDataMember() && !New->isOutOfLine()) { Diag(New->getLocation(), diag::err_duplicate_member) << New->getIdentifier(); Diag(Old->getLocation(), diag::note_previous_declaration); New->setInvalidDecl(); } mergeDeclAttributes(New, Old); // Warn if an already-declared variable is made a weak_import in a subsequent // declaration if (New->hasAttr() && Old->getStorageClass() == SC_None && !Old->hasAttr()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); // Remove weak_import attribute on new declaration. New->dropAttr(); } // Merge the types. VarDecl *MostRecent = Old->getMostRecentDecl(); if (MostRecent != Old) { MergeVarDeclTypes(New, MostRecent, mergeTypeWithPrevious(*this, New, MostRecent, Previous)); if (New->isInvalidDecl()) return; } MergeVarDeclTypes(New, Old, mergeTypeWithPrevious(*this, New, Old, Previous)); if (New->isInvalidDecl()) return; diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = getNoteDiagForInvalidRedeclaration(Old, New); // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && !New->isStaticDataMember() && Old->hasExternalFormalLinkage()) { if (getLangOpts().MicrosoftExt) { Diag(New->getLocation(), diag::ext_static_non_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } } // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that // identifier is visible,23) if the prior declaration specifies // internal or external linkage, the linkage of the identifier at // the later declaration is the same as the linkage specified at // the prior declaration. If no prior declaration is visible, or // if the prior declaration specifies no linkage, then the // identifier has external linkage. if (New->hasExternalStorage() && Old->hasLinkage()) /* Okay */; else if (New->getCanonicalDecl()->getStorageClass() != SC_Static && !New->isStaticDataMember() && Old->getCanonicalDecl()->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } // Check if extern is followed by non-extern and vice-versa. if (New->hasExternalStorage() && !Old->hasLinkage() && Old->isLocalVarDeclOrParm()) { Diag(New->getLocation(), diag::err_extern_non_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (Old->hasLinkage() && New->isLocalVarDeclOrParm() && !New->hasExternalStorage()) { Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. // FIXME: The test for external storage here seems wrong? We still // need to check for mismatches. if (!New->hasExternalStorage() && !New->isFileVarDecl() && // Don't complain about out-of-line definitions of static members. !(Old->getLexicalDeclContext()->isRecord() && !New->getLexicalDeclContext()->isRecord())) { Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(OldLocation, PrevDiag); return New->setInvalidDecl(); } if (New->getTLSKind() != Old->getTLSKind()) { if (!Old->getTLSKind()) { Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else if (!New->getTLSKind()) { Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); Diag(OldLocation, PrevDiag); } else { // Do not allow redeclaration to change the variable between requiring // static and dynamic initialization. // FIXME: GCC allows this, but uses the TLS keyword on the first // declaration to determine the kind. Do we need to be compatible here? Diag(New->getLocation(), diag::err_thread_thread_different_kind) << New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic); Diag(OldLocation, PrevDiag); } } // C++ doesn't have tentative definitions, so go right ahead and check here. const VarDecl *Def; if (getLangOpts().CPlusPlus && New->isThisDeclarationADefinition() == VarDecl::Definition && (Def = Old->getDefinition())) { Diag(New->getLocation(), diag::err_redefinition) << New; Diag(Def->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return; } if (haveIncompatibleLanguageLinkages(Old, New)) { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(OldLocation, PrevDiag); New->setInvalidDecl(); return; } // Merge "used" flag. if (Old->getMostRecentDecl()->isUsed(false)) New->setIsUsed(); // Keep a chain of previous declarations. New->setPreviousDecl(Old); if (NewTemplate) NewTemplate->setPreviousDecl(OldTemplate); // Inherit access appropriately. New->setAccess(Old->getAccess()); if (NewTemplate) NewTemplate->setAccess(New->getAccess()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg()); } static void HandleTagNumbering(Sema &S, const TagDecl *Tag, Scope *TagScope) { if (!S.Context.getLangOpts().CPlusPlus) return; if (isa(Tag->getParent())) { // If this tag is the direct child of a class, number it if // it is anonymous. if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl()) return; MangleNumberingContext &MCtx = S.Context.getManglingNumberContext(Tag->getParent()); S.Context.setManglingNumber( Tag, MCtx.getManglingNumber(Tag, TagScope->getMSLocalManglingNumber())); return; } // If this tag isn't a direct child of a class, number it if it is local. Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = S.getCurrentMangleNumberContext(Tag->getDeclContext(), ManglingContextDecl)) { S.Context.setManglingNumber( Tag, MCtx->getManglingNumber(Tag, TagScope->getMSLocalManglingNumber())); } } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation) { Decl *TagD = nullptr; TagDecl *Tag = nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); if (!TagD) // We probably had an error return nullptr; // Note that the above type specs guarantee that the // type rep is a Decl, whereas in many of the others // it's a Type. if (isa(TagD)) Tag = cast(TagD); else if (ClassTemplateDecl *CTD = dyn_cast(TagD)) Tag = CTD->getTemplatedDecl(); } if (Tag) { HandleTagNumbering(*this, Tag, S); Tag->setFreeStanding(); if (Tag->isInvalidDecl()) return Tag; } if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." if (TypeQuals & DeclSpec::TQ_restrict) Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer_noarg) << DS.getSourceRange(); } if (DS.isConstexprSpecified()) { // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations // and definitions of functions and variables. if (Tag) Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. return TagD; } DiagnoseFunctionSpecifiers(DS); if (DS.isFriendSpecified()) { // If we're dealing with a decl but not a TagDecl, assume that // whatever routines created it handled the friendship aspect. if (TagD && !Tag) return nullptr; return ActOnFriendTypeDecl(S, DS, TemplateParams); } CXXScopeSpec &SS = DS.getTypeSpecScope(); bool IsExplicitSpecialization = !TemplateParams.empty() && TemplateParams.back()->size() == 0; if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() && !IsExplicitInstantiation && !IsExplicitSpecialization) { // Per C++ [dcl.type.elab]p1, a class declaration cannot have a // nested-name-specifier unless it is an explicit instantiation // or an explicit specialization. // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either. Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4) << SS.getRange(); return nullptr; } // Track whether this decl-specifier declares anything. bool DeclaresAnything = true; // Handle anonymous struct definitions. if (RecordDecl *Record = dyn_cast_or_null(Tag)) { if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOpts().CPlusPlus || Record->getDeclContext()->isRecord()) return BuildAnonymousStructOrUnion(S, DS, AS, Record, Context.getPrintingPolicy()); DeclaresAnything = false; } } // C11 6.7.2.1p2: // A struct-declaration that does not declare an anonymous structure or // anonymous union shall contain a struct-declarator-list. // // This rule also existed in C89 and C99; the grammar for struct-declaration // did not permit a struct-declaration without a struct-declarator-list. if (!getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Check for Microsoft C extension: anonymous struct/union member. // Handle 2 kinds of anonymous struct/union: // struct STRUCT; // union UNION; // and // STRUCT_TYPE; <- where STRUCT_TYPE is a typedef struct. // UNION_TYPE; <- where UNION_TYPE is a typedef union. if ((Tag && Tag->getDeclName()) || DS.getTypeSpecType() == DeclSpec::TST_typename) { RecordDecl *Record = nullptr; if (Tag) Record = dyn_cast(Tag); else if (const RecordType *RT = DS.getRepAsType().get()->getAsStructureType()) Record = RT->getDecl(); else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) Record = UT->getDecl(); if (Record && getLangOpts().MicrosoftExt) { Diag(DS.getLocStart(), diag::ext_ms_anonymous_record) << Record->isUnion() << DS.getSourceRange(); return BuildMicrosoftCAnonymousStruct(S, DS, Record); } DeclaresAnything = false; } } // Skip all the checks below if we have a type error. if (DS.getTypeSpecType() == DeclSpec::TST_error || (TagD && TagD->isInvalidDecl())) return TagD; if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null(Tag)) if (Enum->enumerator_begin() == Enum->enumerator_end() && !Enum->getIdentifier() && !Enum->isInvalidDecl()) DeclaresAnything = false; if (!DS.isMissingDeclaratorOk()) { // Customize diagnostic for a typedef missing a name. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) Diag(DS.getLocStart(), diag::ext_typedef_without_a_name) << DS.getSourceRange(); else DeclaresAnything = false; } if (DS.isModulePrivateSpecified() && Tag && Tag->getDeclContext()->isFunctionOrMethod()) Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class) << Tag->getTagKind() << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc()); ActOnDocumentableDecl(TagD); // C 6.7/2: // A declaration [...] shall declare at least a declarator [...], a tag, // or the members of an enumeration. // C++ [dcl.dcl]p3: // [If there are no declarators], and except for the declaration of an // unnamed bit-field, the decl-specifier-seq shall introduce one or more // names into the program, or shall redeclare a name introduced by a // previous declaration. if (!DeclaresAnything) { // In C, we allow this as a (popular) extension / bug. Don't bother // producing further diagnostics for redundant qualifiers after this. Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange(); return TagD; } // C++ [dcl.stc]p1: // If a storage-class-specifier appears in a decl-specifier-seq, [...] the // init-declarator-list of the declaration shall not be empty. // C++ [dcl.fct.spec]p1: // If a cv-qualifier appears in a decl-specifier-seq, the // init-declarator-list of the declaration shall not be empty. // // Spurious qualifiers here appear to be valid in C. unsigned DiagID = diag::warn_standalone_specifier; if (getLangOpts().CPlusPlus) DiagID = diag::ext_standalone_specifier; // Note that a linkage-specification sets a storage class, but // 'extern "C" struct foo;' is actually valid and not theoretically // useless. if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) { if (SCS == DeclSpec::SCS_mutable) // Since mutable is not a viable storage class specifier in C, there is // no reason to treat it as an extension. Instead, diagnose as an error. Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_nonmember); else if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef) Diag(DS.getStorageClassSpecLoc(), DiagID) << DeclSpec::getSpecifierName(SCS); } if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) Diag(DS.getThreadStorageClassSpecLoc(), DiagID) << DeclSpec::getSpecifierName(TSCS); if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), DiagID) << "const"; if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getConstSpecLoc(), DiagID) << "volatile"; // Restrict is covered above. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic"; } // Warn about ignored type attributes, for example: // __attribute__((aligned)) struct A; // Attributes should be placed after tag to apply to type declaration. if (!DS.getAttributes().empty()) { DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { AttributeList* attrs = DS.getAttributes().getList(); while (attrs) { Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored) << attrs->getName() << (TypeSpecType == DeclSpec::TST_class ? 0 : TypeSpecType == DeclSpec::TST_struct ? 1 : TypeSpecType == DeclSpec::TST_union ? 2 : TypeSpecType == DeclSpec::TST_interface ? 3 : 4); attrs = attrs->getNext(); } } } return TagD; } /// We are trying to inject an anonymous member into the given scope; /// check if there's an existing declaration that can't be overloaded. /// /// \return true if this is a forbidden redeclaration static bool CheckAnonMemberRedeclaration(Sema &SemaRef, Scope *S, DeclContext *Owner, DeclarationName Name, SourceLocation NameLoc, unsigned diagnostic) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupMemberName, Sema::ForRedeclaration); if (!SemaRef.LookupName(R, S)) return false; if (R.getAsSingle()) return false; // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); assert(PrevDecl && "Expected a non-null Decl"); if (!SemaRef.isDeclInScope(PrevDecl, Owner, S)) return false; SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); return true; } /// InjectAnonymousStructOrUnionMembers - Inject the members of the /// anonymous struct or union AnonRecord into the owning context Owner /// and scope S. This routine will be invoked just after we realize /// that an unnamed union or struct is actually an anonymous union or /// struct, e.g., /// /// @code /// union { /// int i; /// float f; /// }; // InjectAnonymousStructOrUnionMembers called here to inject i and /// // f into the surrounding scope.x /// @endcode /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, AccessSpecifier AS, SmallVectorImpl &Chaining, bool MSAnonStruct) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; bool Invalid = false; // Look every FieldDecl and IndirectFieldDecl with a name. for (auto *D : AnonRecord->decls()) { if ((isa(D) || isa(D)) && cast(D)->getDeclName()) { ValueDecl *VD = cast(D); if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(), VD->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the // scope in which the anonymous union is declared. Invalid = true; } else { // C++ [class.union]p2: // For the purpose of name lookup, after the anonymous union // definition, the members of the anonymous union are // considered to have been defined in the scope in which the // anonymous union is declared. unsigned OldChainingSize = Chaining.size(); if (IndirectFieldDecl *IF = dyn_cast(VD)) for (auto *PI : IF->chain()) Chaining.push_back(PI); else Chaining.push_back(VD); assert(Chaining.size() >= 2); NamedDecl **NamedChain = new (SemaRef.Context)NamedDecl*[Chaining.size()]; for (unsigned i = 0; i < Chaining.size(); i++) NamedChain[i] = Chaining[i]; IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(), VD->getType(), NamedChain, Chaining.size()); for (const auto *Attr : VD->attrs()) IndirectField->addAttr(Attr->clone(SemaRef.Context)); IndirectField->setAccess(AS); IndirectField->setImplicit(); SemaRef.PushOnScopeChains(IndirectField, S); // That includes picking up the appropriate access specifier. if (AS != AS_none) IndirectField->setAccess(AS); Chaining.resize(OldChainingSize); } } } return Invalid; } /// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to /// a VarDecl::StorageClass. Any error reporting is up to the caller: /// illegal input values are mapped to SC_None. static StorageClass StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) { DeclSpec::SCS StorageClassSpec = DS.getStorageClassSpec(); assert(StorageClassSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; case DeclSpec::SCS_extern: if (DS.isExternInLinkageSpec()) return SC_None; return SC_Extern; case DeclSpec::SCS_static: return SC_Static; case DeclSpec::SCS_auto: return SC_Auto; case DeclSpec::SCS_register: return SC_Register; case DeclSpec::SCS_private_extern: return SC_PrivateExtern; // Illegal SCSs map to None: error reporting is up to the caller. case DeclSpec::SCS_mutable: // Fall through. case DeclSpec::SCS_typedef: return SC_None; } llvm_unreachable("unknown storage class specifier"); } static SourceLocation findDefaultInitializer(const CXXRecordDecl *Record) { assert(Record->hasInClassInitializer()); for (const auto *I : Record->decls()) { const auto *FD = dyn_cast(I); if (const auto *IFD = dyn_cast(I)) FD = IFD->getAnonField(); if (FD && FD->hasInClassInitializer()) return FD->getLocation(); } llvm_unreachable("couldn't find in-class initializer"); } static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, SourceLocation DefaultInitLoc) { if (!Parent->isUnion() || !Parent->hasInClassInitializer()) return; S.Diag(DefaultInitLoc, diag::err_multiple_mem_union_initialization); S.Diag(findDefaultInitializer(Parent), diag::note_previous_initializer) << 0; } static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, CXXRecordDecl *AnonUnion) { if (!Parent->isUnion() || !Parent->hasInClassInitializer()) return; checkDuplicateDefaultInit(S, Parent, findDefaultInitializer(AnonUnion)); } /// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a C11 feature; anonymous structures /// are a C11 feature and GNU C++ extension. Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy) { DeclContext *Owner = Record->getDeclContext(); // Diagnose whether this anonymous struct/union is an extension. if (Record->isUnion() && !getLangOpts().CPlusPlus && !getLangOpts().C11) Diag(Record->getLocation(), diag::ext_anonymous_union); else if (!Record->isUnion() && getLangOpts().CPlusPlus) Diag(Record->getLocation(), diag::ext_gnu_anonymous_struct); else if (!Record->isUnion() && !getLangOpts().C11) Diag(Record->getLocation(), diag::ext_c11_anonymous_struct); // C and C++ require different kinds of checks for anonymous // structs/unions. bool Invalid = false; if (getLangOpts().CPlusPlus) { const char *PrevSpec = nullptr; unsigned DiagID; if (Record->isUnion()) { // C++ [class.union]p6: // Anonymous unions declared in a named namespace or in the // global namespace shall be declared static. if (DS.getStorageClassSpec() != DeclSpec::SCS_static && (isa(Owner) || (isa(Owner) && cast(Owner)->getDeclName()))) { Diag(Record->getLocation(), diag::err_anonymous_union_not_static) << FixItHint::CreateInsertion(Record->getLocation(), "static "); // Recover by adding 'static'. DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(), PrevSpec, DiagID, Policy); } // C++ [class.union]p6: // A storage class is not allowed in a declaration of an // anonymous union in a class scope. else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && isa(Owner)) { Diag(DS.getStorageClassSpecLoc(), diag::err_anonymous_union_with_storage_spec) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); // Recover by removing the storage specifier. DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(), PrevSpec, DiagID, Context.getPrintingPolicy()); } } // Ignore const/volatile/restrict qualifiers. if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "const" << FixItHint::CreateRemoval(DS.getConstSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "volatile" << FixItHint::CreateRemoval(DS.getVolatileSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict) Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "restrict" << FixItHint::CreateRemoval(DS.getRestrictSpecLoc()); if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(DS.getAtomicSpecLoc(), diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "_Atomic" << FixItHint::CreateRemoval(DS.getAtomicSpecLoc()); DS.ClearTypeQualifiers(); } // C++ [class.union]p2: // The member-specification of an anonymous union shall only // define non-static data members. [Note: nested types and // functions cannot be declared within an anonymous union. ] for (auto *Mem : Record->decls()) { if (auto *FD = dyn_cast(Mem)) { // C++ [class.union]p3: // An anonymous union shall not have private or protected // members (clause 11). assert(FD->getAccess() != AS_none); if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); Invalid = true; } // C++ [class.union]p1 // An object of a class with a non-trivial constructor, a non-trivial // copy constructor, a non-trivial destructor, or a non-trivial copy // assignment operator cannot be a member of a union, nor can an // array of such objects. if (CheckNontrivialField(FD)) Invalid = true; } else if (Mem->isImplicit()) { // Any implicit members are fine. } else if (isa(Mem) && Mem->getDeclContext() != Record) { // This is a type that showed up in an // elaborated-type-specifier inside the anonymous struct or // union, but which actually declares a type outside of the // anonymous struct or union. It's okay. } else if (auto *MemRecord = dyn_cast(Mem)) { if (!MemRecord->isAnonymousStructOrUnion() && MemRecord->getDeclName()) { // Visual C++ allows type definition in anonymous struct or union. if (getLangOpts().MicrosoftExt) Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); else { // This is a nested type declaration. Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) << (int)Record->isUnion(); Invalid = true; } } else { // This is an anonymous type definition within another anonymous type. // This is a popular extension, provided by Plan9, MSVC and GCC, but // not part of standard C++. Diag(MemRecord->getLocation(), diag::ext_anonymous_record_with_anonymous_type) << (int)Record->isUnion(); } } else if (isa(Mem)) { // Any access specifier is fine. } else if (isa(Mem)) { // In C++1z, static_assert declarations are also fine. } else { // We have something that isn't a non-static data // member. Complain about it. unsigned DK = diag::err_anonymous_record_bad_member; if (isa(Mem)) DK = diag::err_anonymous_record_with_type; else if (isa(Mem)) DK = diag::err_anonymous_record_with_function; else if (isa(Mem)) DK = diag::err_anonymous_record_with_static; // Visual C++ allows type definition in anonymous struct or union. if (getLangOpts().MicrosoftExt && DK == diag::err_anonymous_record_with_type) Diag(Mem->getLocation(), diag::ext_anonymous_record_with_type) << (int)Record->isUnion(); else { Diag(Mem->getLocation(), DK) << (int)Record->isUnion(); Invalid = true; } } } // C++11 [class.union]p8 (DR1460): // At most one variant member of a union may have a // brace-or-equal-initializer. if (cast(Record)->hasInClassInitializer() && Owner->isRecord()) checkDuplicateDefaultInit(*this, cast(Owner), cast(Record)); } if (!Record->isUnion() && !Owner->isRecord()) { Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) << (int)getLangOpts().CPlusPlus; Invalid = true; } // Mock up a declarator. Declarator Dc(DS, Declarator::MemberContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct/union"); // Create a declaration for this anonymous struct/union. NamedDecl *Anon = nullptr; if (RecordDecl *OwningClass = dyn_cast(Owner)) { Anon = FieldDecl::Create(Context, OwningClass, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); if (getLangOpts().CPlusPlus) FieldCollector->Add(cast(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(Record->getLocation(), diag::err_mutable_nonmember); Invalid = true; SC = SC_None; } Anon = VarDecl::Create(Context, Owner, DS.getLocStart(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, SC); // Default-initialize the implicit variable. This initialization will be // trivial in almost all cases, except if a union member has an in-class // initializer: // union { int n = 0; }; ActOnUninitializedDecl(Anon, /*TypeMayContainAuto=*/false); } Anon->setImplicit(); // Mark this as an anonymous struct/union type. Record->setAnonymousStructOrUnion(true); // Add the anonymous struct/union object to the current // context. We'll be referencing this object when we refer to one of // its members. Owner->addDecl(Anon); // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. SmallVector Chain; Chain.push_back(Anon); if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain, false)) Invalid = true; if (VarDecl *NewVD = dyn_cast(Anon)) { if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(NewVD->getDeclContext(), ManglingContextDecl)) { Context.setManglingNumber(NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber())); Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); } } } if (Invalid) Anon->setInvalidDecl(); return Anon; } /// BuildMicrosoftCAnonymousStruct - Handle the declaration of an /// Microsoft C anonymous structure. /// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx /// Example: /// /// struct A { int a; }; /// struct B { struct A; int b; }; /// /// void foo() { /// B var; /// var.a = 3; /// } /// Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) { assert(Record && "expected a record!"); // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); auto *ParentDecl = cast(CurContext); QualType RecTy = Context.getTypeDeclType(Record); // Create a declaration for this anonymous struct. NamedDecl *Anon = FieldDecl::Create(Context, ParentDecl, DS.getLocStart(), DS.getLocStart(), /*IdentifierInfo=*/nullptr, RecTy, TInfo, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setImplicit(); // Add the anonymous struct object to the current context. CurContext->addDecl(Anon); // Inject the members of the anonymous struct into the current // context and into the identifier resolver chain for name lookup // purposes. SmallVector Chain; Chain.push_back(Anon); RecordDecl *RecordDef = Record->getDefinition(); if (RequireCompleteType(Anon->getLocation(), RecTy, diag::err_field_incomplete) || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, AS_none, Chain, true)) { Anon->setInvalidDecl(); ParentDecl->setInvalidDecl(); } return Anon; } /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. DeclarationNameInfo Sema::GetNameForDeclarator(Declarator &D) { return GetNameFromUnqualifiedId(D.getName()); } /// \brief Retrieves the declaration name from a parsed unqualified-id. DeclarationNameInfo Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { DeclarationNameInfo NameInfo; NameInfo.setLoc(Name.StartLocation); switch (Name.getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: NameInfo.setName(Name.Identifier); NameInfo.setLoc(Name.StartLocation); return NameInfo; case UnqualifiedId::IK_OperatorFunctionId: NameInfo.setName(Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator)); NameInfo.setLoc(Name.StartLocation); NameInfo.getInfo().CXXOperatorName.BeginOpNameLoc = Name.OperatorFunctionId.SymbolLocations[0]; NameInfo.getInfo().CXXOperatorName.EndOpNameLoc = Name.EndLocation.getRawEncoding(); return NameInfo; case UnqualifiedId::IK_LiteralOperatorId: NameInfo.setName(Context.DeclarationNames.getCXXLiteralOperatorName( Name.Identifier)); NameInfo.setLoc(Name.StartLocation); NameInfo.setCXXLiteralOperatorNameLoc(Name.EndLocation); return NameInfo; case UnqualifiedId::IK_ConversionFunctionId: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.ConversionFunctionId, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXConversionFunctionName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_ConstructorName: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.ConstructorName, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_ConstructorTemplateId: { // In well-formed code, we can only have a constructor // template-id that refers to the current context, so go there // to find the actual type being constructed. CXXRecordDecl *CurClass = dyn_cast(CurContext); if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) return DeclarationNameInfo(); // Determine the type of the class being constructed. QualType CurClassType = Context.getTypeDeclType(CurClass); // FIXME: Check two things: that the template-id names the same type as // CurClassType, and that the template-id does not occur when the name // was qualified. NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(CurClassType))); NameInfo.setLoc(Name.StartLocation); // FIXME: should we retrieve TypeSourceInfo? NameInfo.setNamedTypeInfo(nullptr); return NameInfo; } case UnqualifiedId::IK_DestructorName: { TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(Name.DestructorName, &TInfo); if (Ty.isNull()) return DeclarationNameInfo(); NameInfo.setName(Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(Ty))); NameInfo.setLoc(Name.StartLocation); NameInfo.setNamedTypeInfo(TInfo); return NameInfo; } case UnqualifiedId::IK_TemplateId: { TemplateName TName = Name.TemplateId->Template.get(); SourceLocation TNameLoc = Name.TemplateId->TemplateNameLoc; return Context.getNameForTemplate(TName, TNameLoc); } } // switch (Name.getKind()) llvm_unreachable("Unknown name kind"); } static QualType getCoreType(QualType Ty) { do { if (Ty->isPointerType() || Ty->isReferenceType()) Ty = Ty->getPointeeType(); else if (Ty->isArrayType()) Ty = Ty->castAsArrayTypeUnsafe()->getElementType(); else return Ty.withoutLocalFastQualifiers(); } while (true); } /// hasSimilarParameters - Determine whether the C++ functions Declaration /// and Definition have "nearly" matching parameters. This heuristic is /// used to improve diagnostics in the case where an out-of-line function /// definition doesn't match any declaration within the class or namespace. /// Also sets Params to the list of indices to the parameters that differ /// between the declaration and the definition. If hasSimilarParameters /// returns true and Params is empty, then all of the parameters match. static bool hasSimilarParameters(ASTContext &Context, FunctionDecl *Declaration, FunctionDecl *Definition, SmallVectorImpl &Params) { Params.clear(); if (Declaration->param_size() != Definition->param_size()) return false; for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); // The parameter types are identical if (Context.hasSameType(DefParamTy, DeclParamTy)) continue; QualType DeclParamBaseTy = getCoreType(DeclParamTy); QualType DefParamBaseTy = getCoreType(DefParamTy); const IdentifierInfo *DeclTyName = DeclParamBaseTy.getBaseTypeIdentifier(); const IdentifierInfo *DefTyName = DefParamBaseTy.getBaseTypeIdentifier(); if (Context.hasSameUnqualifiedType(DeclParamBaseTy, DefParamBaseTy) || (DeclTyName && DeclTyName == DefTyName)) Params.push_back(Idx); else // The two parameters aren't even close return false; } return true; } /// NeedsRebuildingInCurrentInstantiation - Checks whether the given /// declarator needs to be rebuilt in the current instantiation. /// Any bits of declarator which appear before the name are valid for /// consideration here. That's specifically the type in the decl spec /// and the base type in any member-pointer chunks. static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, DeclarationName Name) { // The types we specifically need to rebuild are: // - typenames, typeofs, and decltypes // - types which will become injected class names // Of course, we also need to rebuild any type referencing such a // type. It's safest to just say "dependent", but we call out a // few cases here. DeclSpec &DS = D.getMutableDeclSpec(); switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: case DeclSpec::TST_underlyingType: case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = nullptr; QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); if (T.isNull() || !T->isDependentType()) break; // Make sure there's a type source info. This isn't really much // of a waste; most dependent types should have type source info // attached already. if (!TSI) TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc()); // Rebuild the type in the current instantiation. TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name); if (!TSI) return true; // Store the new type back in the decl spec. ParsedType LocType = S.CreateParsedType(TSI->getType(), TSI); DS.UpdateTypeRep(LocType); break; } case DeclSpec::TST_decltype: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); ExprResult Result = S.RebuildExprInCurrentInstantiation(E); if (Result.isInvalid()) return true; DS.UpdateExprRep(Result.get()); break; } default: // Nothing to do for these decl specs. break; } // It doesn't matter what order we do this in. for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { DeclaratorChunk &Chunk = D.getTypeObject(I); // The only type information in the declarator which can come // before the declaration name is the base type of a member // pointer. if (Chunk.Kind != DeclaratorChunk::MemberPointer) continue; // Rebuild the scope specifier in-place. CXXScopeSpec &SS = Chunk.Mem.Scope(); if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS)) return true; } return false; } Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FDK_Declaration); Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); return Dcl; } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: /// If T is the name of a class, then each of the following shall have a /// name different from T: /// - every static data member of class T; /// - every member function of class T /// - every member of class T that is itself a type; /// \returns true if the declaration name violates these rules. bool Sema::DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo NameInfo) { DeclarationName Name = NameInfo.getName(); if (CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getIdentifier() && Record->getDeclName() == Name) { Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name; return true; } return false; } /// \brief Diagnose a declaration whose declarator-id has the given /// nested-name-specifier. /// /// \param SS The nested-name-specifier of the declarator-id. /// /// \param DC The declaration context to which the nested-name-specifier /// resolves. /// /// \param Name The name of the entity being declared. /// /// \param Loc The location of the name of the entity being declared. /// /// \returns true if we cannot safely recover from this error, false otherwise. bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc) { DeclContext *Cur = CurContext; while (isa(Cur) || isa(Cur)) Cur = Cur->getParent(); // If the user provided a superfluous scope specifier that refers back to the // class in which the entity is already declared, diagnose and ignore it. // // class X { // void X::f(); // }; // // Note, it was once ill-formed to give redundant qualification in all // contexts, but that rule was removed by DR482. if (Cur->Equals(DC)) { if (Cur->isRecord()) { Diag(Loc, LangOpts.MicrosoftExt ? diag::warn_member_extra_qualification : diag::err_member_extra_qualification) << Name << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); } else { Diag(Loc, diag::warn_namespace_member_extra_qualification) << Name; } return false; } // Check whether the qualifying scope encloses the scope of the original // declaration. if (!Cur->Encloses(DC)) { if (Cur->isRecord()) Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); else if (isa(DC)) Diag(Loc, diag::err_invalid_declarator_global_scope) << Name << SS.getRange(); else if (isa(Cur)) Diag(Loc, diag::err_invalid_declarator_in_function) << Name << SS.getRange(); else if (isa(Cur)) Diag(Loc, diag::err_invalid_declarator_in_block) << Name << SS.getRange(); else Diag(Loc, diag::err_invalid_declarator_scope) << Name << cast(Cur) << cast(DC) << SS.getRange(); return true; } if (Cur->isRecord()) { // Cannot qualify members within a class. Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); SS.clear(); // C++ constructors and destructors with incorrect scopes can break // our AST invariants by having the wrong underlying types. If // that's the case, then drop this declaration entirely. if ((Name.getNameKind() == DeclarationName::CXXConstructorName || Name.getNameKind() == DeclarationName::CXXDestructorName) && !Context.hasSameType(Name.getCXXNameType(), Context.getTypeDeclType(cast(Cur)))) return true; return false; } // C++11 [dcl.meaning]p1: // [...] "The nested-name-specifier of the qualified declarator-id shall // not begin with a decltype-specifer" NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data()); while (SpecLoc.getPrefix()) SpecLoc = SpecLoc.getPrefix(); if (dyn_cast_or_null( SpecLoc.getNestedNameSpecifier()->getAsType())) Diag(Loc, diag::err_decltype_in_declarator) << SpecLoc.getTypeLoc().getSourceRange(); return false; } NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. if (!Name) { if (!D.isInvalidType()) // Reject this if we think it is valid. Diag(D.getDeclSpec().getLocStart(), diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return nullptr; } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) return nullptr; // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. while ((S->getFlags() & Scope::DeclScope) == 0 || (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); DeclContext *DC = CurContext; if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); else if (D.getCXXScopeSpec().isSet()) { if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), UPPC_DeclarationQualifier)) return nullptr; bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); if (!DC || isa(DC)) { // If we could not compute the declaration context, it's because the // declaration context is dependent but does not refer to a class, // class template, or class template partial specialization. Complain // and return early, to avoid the coming semantic disaster. Diag(D.getIdentifierLoc(), diag::err_template_qualified_declarator_no_match) << D.getCXXScopeSpec().getScopeRep() << D.getCXXScopeSpec().getRange(); return nullptr; } bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return nullptr; if (isa(DC) && !cast(DC)->hasDefinition()) { Diag(D.getIdentifierLoc(), diag::err_member_def_undefined_record) << Name << DC << D.getCXXScopeSpec().getRange(); D.setInvalidType(); } else if (!D.getDeclSpec().isFriendSpecified()) { if (diagnoseQualifiedDeclaration(D.getCXXScopeSpec(), DC, Name, D.getIdentifierLoc())) { if (DC->isRecord()) return nullptr; D.setInvalidType(); } } // Check whether we need to rebuild the type of the given // declaration in the current instantiation. if (EnteringContext && IsDependentContext && TemplateParamLists.size() != 0) { ContextRAII SavedContext(*this, DC); if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name)) D.setInvalidType(); } } if (DiagnoseClassNameShadow(DC, NameInfo)) // If this is a typedef, we'll end up spewing multiple diagnostics. // Just return early; it's safer. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return nullptr; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DeclarationType)) D.setInvalidType(); LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); // See if this is a redefinition of a variable in the same scope. if (!D.getCXXScopeSpec().isSet()) { bool IsLinkageLookup = false; bool CreateBuiltins = false; // If the declaration we're planning to build will be a function // or object with linkage, then look for another declaration with // linkage (C99 6.2.2p4-5 and C++ [basic.link]p6). // // If the declaration we're planning to build will be declared with // external linkage in the translation unit, create any builtin with // the same name. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) /* Do nothing*/; else if (CurContext->isFunctionOrMethod() && (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern || R->isFunctionType())) { IsLinkageLookup = true; CreateBuiltins = CurContext->getEnclosingNamespaceContext()->isTranslationUnit(); } else if (CurContext->getRedeclContext()->isTranslationUnit() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) CreateBuiltins = true; if (IsLinkageLookup) Previous.clear(LookupRedeclarationWithLinkage); LookupName(Previous, S, CreateBuiltins); } else { // Something like "int foo::x;" LookupQualifiedName(Previous, DC); // C++ [dcl.meaning]p1: // When the declarator-id is qualified, the declaration shall refer to a // previously declared member of the class or namespace to which the // qualifier refers (or, in the case of a namespace, of an element of the // inline namespace set of that namespace (7.3.1)) or to a specialization // thereof; [...] // // Note that we already checked the context above, and that we do not have // enough information to make sure that Previous contains the declaration // we want to match. For example, given: // // class X { // void f(); // void f(float); // }; // // void X::f(int) { } // ill-formed // // In this case, Previous will point to the overload set // containing the two f's declared in X, but neither of them // matches. // C++ [dcl.meaning]p1: // [...] the member shall not merely have been introduced by a // using-declaration in the scope of the class or namespace nominated by // the nested-name-specifier of the declarator-id. RemoveUsingDecls(Previous); } if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. if (!D.isInvalidType()) DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. Previous.clear(); } // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (Previous.isSingleTagDecl() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) Previous.clear(); // Check that there are no default arguments other than in the parameters // of a function declaration (C++ only). if (getLangOpts().CPlusPlus) CheckExtraCXXDefaultArguments(D); NamedDecl *New; bool AddToScope = true; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return nullptr; } New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, AddToScope); } else { New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, AddToScope); } if (!New) return nullptr; // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. if (New->getDeclName() && AddToScope && !(D.isRedeclaration() && New->isInvalidDecl())) { // Only make a locally-scoped extern declaration visible if it is the first // declaration of this entity. Qualified lookup for such an entity should // only find this declaration if there is no visible declaration of it. bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl(); PushOnScopeChains(New, S, AddToContext); if (!AddToContext) CurContext->addHiddenDecl(New); } return New; } /// Helper method to turn variable array types into constant array /// types in certain situations which would otherwise be errors (for /// GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, bool &SizeIsNegative, llvm::APSInt &Oversized) { // This method tries to turn a variable array into a constant // array even when the size isn't an ICE. This is necessary // for compatibility with code that depends on gcc's buggy // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; Oversized = 0; if (T->isDependentType()) return QualType(); QualifierCollector Qs; const Type *Ty = Qs.strip(T); if (const PointerType* PTy = dyn_cast(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); return Qs.apply(Context, FixedType); } if (const ParenType* PTy = dyn_cast(Ty)) { QualType Inner = PTy->getInnerType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Inner, Context, SizeIsNegative, Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getParenType(FixedType); return Qs.apply(Context, FixedType); } const VariableArrayType* VLATy = dyn_cast(T); if (!VLATy) return QualType(); // FIXME: We should probably handle this case if (VLATy->getElementType()->isVariablyModifiedType()) return QualType(); llvm::APSInt Res; if (!VLATy->getSizeExpr() || !VLATy->getSizeExpr()->EvaluateAsInt(Res, Context)) return QualType(); // Check whether the array size is negative. if (Res.isSigned() && Res.isNegative()) { SizeIsNegative = true; return QualType(); } // Check whether the array is too large to be addressed. unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(), Res); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { Oversized = Res; return QualType(); } return Context.getConstantArrayType(VLATy->getElementType(), Res, ArrayType::Normal, 0); } static void FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) { if (PointerTypeLoc SrcPTL = SrcTL.getAs()) { PointerTypeLoc DstPTL = DstTL.castAs(); FixInvalidVariablyModifiedTypeLoc(SrcPTL.getPointeeLoc(), DstPTL.getPointeeLoc()); DstPTL.setStarLoc(SrcPTL.getStarLoc()); return; } if (ParenTypeLoc SrcPTL = SrcTL.getAs()) { ParenTypeLoc DstPTL = DstTL.castAs(); FixInvalidVariablyModifiedTypeLoc(SrcPTL.getInnerLoc(), DstPTL.getInnerLoc()); DstPTL.setLParenLoc(SrcPTL.getLParenLoc()); DstPTL.setRParenLoc(SrcPTL.getRParenLoc()); return; } ArrayTypeLoc SrcATL = SrcTL.castAs(); ArrayTypeLoc DstATL = DstTL.castAs(); TypeLoc SrcElemTL = SrcATL.getElementLoc(); TypeLoc DstElemTL = DstATL.getElementLoc(); DstElemTL.initializeFullCopy(SrcElemTL); DstATL.setLBracketLoc(SrcATL.getLBracketLoc()); DstATL.setSizeExpr(SrcATL.getSizeExpr()); DstATL.setRBracketLoc(SrcATL.getRBracketLoc()); } /// Helper method to turn variable array types into constant array /// types in certain situations which would otherwise be errors (for /// GCC compatibility). static TypeSourceInfo* TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, ASTContext &Context, bool &SizeIsNegative, llvm::APSInt &Oversized) { QualType FixedTy = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context, SizeIsNegative, Oversized); if (FixedTy.isNull()) return nullptr; TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy); FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(), FixedTInfo->getTypeLoc()); return FixedTInfo; } /// \brief Register the given locally-scoped extern "C" declaration so /// that it can be found later for redeclarations. We include any extern "C" /// declaration that is not visible in the translation unit here, not just /// function-scope declarations. void Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) { if (!getLangOpts().CPlusPlus && ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit()) // Don't need to track declarations in the TU in C. return; // Note that we have a locally-scoped external with this name. // FIXME: There can be multiple such declarations if they are functions marked // __attribute__((overloadable)) declared in function scope in C. LocallyScopedExternCDecls[ND->getDeclName()] = ND; } NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { if (ExternalSource) { // Load locally-scoped external decls from the external source. // FIXME: This is inefficient. Maybe add a DeclContext for extern "C" decls? SmallVector Decls; ExternalSource->ReadLocallyScopedExternCDecls(Decls); for (unsigned I = 0, N = Decls.size(); I != N; ++I) { llvm::DenseMap::iterator Pos = LocallyScopedExternCDecls.find(Decls[I]->getDeclName()); if (Pos == LocallyScopedExternCDecls.end()) LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I]; } } NamedDecl *D = LocallyScopedExternCDecls.lookup(Name); return D ? D->getMostRecentDecl() : nullptr; } /// \brief Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { // FIXME: We should probably indicate the identifier in question to avoid // confusion for constructs like "inline int a(), b;" if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function); if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function); if (DS.isExplicitSpecified()) Diag(DS.getExplicitSpecLoc(), diag::err_explicit_non_function); if (DS.isNoreturnSpecified()) Diag(DS.getNoreturnSpecLoc(), diag::err_noreturn_non_function); } NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) << D.getCXXScopeSpec().getRange(); D.setInvalidType(); // Pretend we didn't see the scope specifier. DC = CurContext; Previous.clear(); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; if (D.getName().Kind != UnqualifiedId::IK_Identifier) { Diag(D.getName().StartLocation, diag::err_typedef_not_identifier) << D.getName().getSourceRange(); return nullptr; } TypedefDecl *NewTD = ParseTypedefDecl(S, D, TInfo->getType(), TInfo); if (!NewTD) return nullptr; // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); CheckTypedefForVariablyModifiedType(S, NewTD); bool Redeclaration = D.isRedeclaration(); NamedDecl *ND = ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); D.setRedeclaration(Redeclaration); return ND; } void Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so // that redeclarations will match. TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo(); QualType T = TInfo->getType(); if (T->isVariablyModifiedType()) { getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == nullptr) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (FixedTInfo) { Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(FixedTInfo); } else { if (SizeIsNegative) Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size); else if (T->isVariableArrayType()) Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope); else if (Oversized.getBoolValue()) Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10); else Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope); NewTD->setInvalidDecl(); } } } } /// ActOnTypedefNameDecl - Perform semantic checking for a declaration which /// declares a typedef-name, either using the 'typedef' type specifier or via /// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. NamedDecl* Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, LookupResult &Previous, bool &Redeclaration) { // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/false, /*AllowInlineNamespace*/false); filterNonConflictingPreviousTypedefDecls(Context, NewTD, Previous); if (!Previous.empty()) { Redeclaration = true; MergeTypedefNameDecl(NewTD, Previous); } // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = NewTD->getIdentifier()) if (!NewTD->isInvalidDecl() && NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (II->isStr("FILE")) Context.setFILEDecl(NewTD); else if (II->isStr("jmp_buf")) Context.setjmp_bufDecl(NewTD); else if (II->isStr("sigjmp_buf")) Context.setsigjmp_bufDecl(NewTD); else if (II->isStr("ucontext_t")) Context.setucontext_tDecl(NewTD); } return NewTD; } /// \brief Determines whether the given declaration is an out-of-scope /// previous declaration. /// /// This routine should be invoked when name lookup has found a /// previous declaration (PrevDecl) that is not in the scope where a /// new declaration by the same name is being introduced. If the new /// declaration occurs in a local scope, previous declarations with /// linkage may still be considered previous declarations (C99 /// 6.2.2p4-5, C++ [basic.link]p6). /// /// \param PrevDecl the previous declaration found by name /// lookup /// /// \param DC the context in which the new declaration is being /// declared. /// /// \returns true if PrevDecl is an out-of-scope previous declaration /// for a new delcaration with the same name. static bool isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, ASTContext &Context) { if (!PrevDecl) return false; if (!PrevDecl->hasLinkage()) return false; if (Context.getLangOpts().CPlusPlus) { // C++ [basic.link]p6: // If there is a visible declaration of an entity with linkage // having the same name and type, ignoring entities declared // outside the innermost enclosing namespace scope, the block // scope declaration declares that same entity and receives the // linkage of the previous declaration. DeclContext *OuterContext = DC->getRedeclContext(); if (!OuterContext->isFunctionOrMethod()) // This rule only applies to block-scope declarations. return false; DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); if (PrevOuterContext->isRecord()) // We found a member function: ignore it. return false; // Find the innermost enclosing namespace for the new and // previous declarations. OuterContext = OuterContext->getEnclosingNamespaceContext(); PrevOuterContext = PrevOuterContext->getEnclosingNamespaceContext(); // The previous declaration is in a different namespace, so it // isn't the same function. if (!OuterContext->Equals(PrevOuterContext)) return false; } return true; } static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { CXXScopeSpec &SS = D.getCXXScopeSpec(); if (!SS.isSet()) return; DD->setQualifierInfo(SS.getWithLocInContext(DD->getASTContext())); } bool Sema::inferObjCARCLifetime(ValueDecl *decl) { QualType type = decl->getType(); Qualifiers::ObjCLifetime lifetime = type.getObjCLifetime(); if (lifetime == Qualifiers::OCL_Autoreleasing) { // Various kinds of declaration aren't allowed to be __autoreleasing. unsigned kind = -1U; if (VarDecl *var = dyn_cast(decl)) { if (var->hasAttr()) kind = 0; // __block else if (!var->hasLocalStorage()) kind = 1; // global } else if (isa(decl)) { kind = 3; // ivar } else if (isa(decl)) { kind = 2; // field } if (kind != -1U) { Diag(decl->getLocation(), diag::err_arc_autoreleasing_var) << kind; } } else if (lifetime == Qualifiers::OCL_None) { // Try to infer lifetime. if (!type->isObjCLifetimeType()) return false; lifetime = type->getObjCARCImplicitLifetime(); type = Context.getLifetimeQualifiedType(type, lifetime); decl->setType(type); } if (VarDecl *var = dyn_cast(decl)) { // Thread-local variables cannot have lifetime. if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && var->getTLSKind()) { Diag(var->getLocation(), diag::err_arc_thread_ownership) << var->getType(); return true; } } return false; } static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // Ensure that an auto decl is deduced otherwise the checks below might cache // the wrong linkage. assert(S.ParsingInitForAutoVars.count(&ND) == 0); // 'weak' only applies to declarations with external linkage. if (WeakAttr *Attr = ND.getAttr()) { if (!ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weak_static); ND.dropAttr(); } } if (WeakRefAttr *Attr = ND.getAttr()) { if (ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static); ND.dropAttr(); } } // 'selectany' only applies to externally visible varable declarations. // It does not apply to functions. if (SelectAnyAttr *Attr = ND.getAttr()) { if (isa(ND) || !ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_selectany_non_extern_data); ND.dropAttr(); } } // dll attributes require external linkage. if (const InheritableAttr *Attr = getDLLAttr(&ND)) { if (!ND.isExternallyVisible()) { S.Diag(ND.getLocation(), diag::err_attribute_dll_not_extern) << &ND << Attr; ND.setInvalidDecl(); } } } static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, bool IsSpecialization) { if (TemplateDecl *OldTD = dyn_cast(OldDecl)) OldDecl = OldTD->getTemplatedDecl(); if (TemplateDecl *NewTD = dyn_cast(NewDecl)) NewDecl = NewTD->getTemplatedDecl(); if (!OldDecl || !NewDecl) return; const DLLImportAttr *OldImportAttr = OldDecl->getAttr(); const DLLExportAttr *OldExportAttr = OldDecl->getAttr(); const DLLImportAttr *NewImportAttr = NewDecl->getAttr(); const DLLExportAttr *NewExportAttr = NewDecl->getAttr(); // dllimport and dllexport are inheritable attributes so we have to exclude // inherited attribute instances. bool HasNewAttr = (NewImportAttr && !NewImportAttr->isInherited()) || (NewExportAttr && !NewExportAttr->isInherited()); // A redeclaration is not allowed to add a dllimport or dllexport attribute, // the only exception being explicit specializations. // Implicitly generated declarations are also excluded for now because there // is no other way to switch these to use dllimport or dllexport. bool AddsAttr = !(OldImportAttr || OldExportAttr) && HasNewAttr; if (AddsAttr && !IsSpecialization && !OldDecl->isImplicit()) { // If the declaration hasn't been used yet, allow with a warning for // free functions and global variables. bool JustWarn = false; if (!OldDecl->isUsed() && !OldDecl->isCXXClassMember()) { auto *VD = dyn_cast(OldDecl); if (VD && !VD->getDescribedVarTemplate()) JustWarn = true; auto *FD = dyn_cast(OldDecl); if (FD && FD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) JustWarn = true; } unsigned DiagID = JustWarn ? diag::warn_attribute_dll_redeclaration : diag::err_attribute_dll_redeclaration; S.Diag(NewDecl->getLocation(), DiagID) << NewDecl << (NewImportAttr ? (const Attr *)NewImportAttr : NewExportAttr); S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); if (!JustWarn) { NewDecl->setInvalidDecl(); return; } } // A redeclaration is not allowed to drop a dllimport attribute, the only // exceptions being inline function definitions, local extern declarations, // and qualified friend declarations. // NB: MSVC converts such a declaration to dllexport. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; if (const auto *VD = dyn_cast(NewDecl)) // Ignore static data because out-of-line definitions are diagnosed // separately. IsStaticDataMember = VD->isStaticDataMember(); else if (const auto *FD = dyn_cast(NewDecl)) { IsInline = FD->isInlined(); IsQualifiedFriend = FD->getQualifier() && FD->getFriendObjectKind() == Decl::FOK_Declared; } if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) << NewDecl << OldImportAttr; S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); OldDecl->dropAttr(); NewDecl->dropAttr(); } else if (IsInline && OldImportAttr && !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { // In MinGW, seeing a function declared inline drops the dllimport attribute. OldDecl->dropAttr(); NewDecl->dropAttr(); S.Diag(NewDecl->getLocation(), diag::warn_dllimport_dropped_from_inline_function) << NewDecl << OldImportAttr; } } /// Given that we are within the definition of the given function, /// will that definition behave like C99's 'inline', where the /// definition is discarded except for optimization purposes? static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) { // Try to avoid calling GetGVALinkageForFunction. // All cases of this require the 'inline' keyword. if (!FD->isInlined()) return false; // This is only possible in C++ with the gnu_inline attribute. if (S.getLangOpts().CPlusPlus && !FD->hasAttr()) return false; // Okay, go ahead and call the relatively-more-expensive function. #ifndef NDEBUG // AST quite reasonably asserts that it's working on a function // definition. We don't really have a way to tell it that we're // currently defining the function, so just lie to it in +Asserts // builds. This is an awful hack. FD->setLazyBody(1); #endif bool isC99Inline = S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; #ifndef NDEBUG FD->setLazyBody(0); #endif return isC99Inline; } /// Determine whether a variable is extern "C" prior to attaching /// an initializer. We can't just call isExternC() here, because that /// will also compute and cache whether the declaration is externally /// visible, which might change when we attach the initializer. /// /// This can only be used if the declaration is known to not be a /// redeclaration of an internal linkage declaration. /// /// For instance: /// /// auto x = []{}; /// /// Attaching the initializer here makes this declaration not externally /// visible, because its type has internal linkage. /// /// FIXME: This is a hack. template static bool isIncompleteDeclExternC(Sema &S, const T *D) { if (S.getLangOpts().CPlusPlus) { // In C++, the overloadable attribute negates the effects of extern "C". if (!D->isInExternCContext() || D->template hasAttr()) return false; } return D->isExternC(); } static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); if (DC->isFunctionOrMethod()) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; if (DC->isRecord()) return false; llvm_unreachable("Unexpected context"); } static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); if (DC->isFileContext() || DC->isFunctionOrMethod()) return true; if (DC->isRecord()) return false; llvm_unreachable("Unexpected context"); } static bool hasParsedAttr(Scope *S, const AttributeList *AttrList, AttributeList::Kind Kind) { for (const AttributeList *L = AttrList; L; L = L->getNext()) if (L->getKind() == Kind) return true; return false; } static bool hasParsedAttr(Scope *S, const Declarator &PD, AttributeList::Kind Kind) { // Check decl attributes on the DeclSpec. if (hasParsedAttr(S, PD.getDeclSpec().getAttributes().getList(), Kind)) return true; // Walk the declarator structure, checking decl attributes that were in a type // position to the decl itself. for (unsigned I = 0, E = PD.getNumTypeObjects(); I != E; ++I) { if (hasParsedAttr(S, PD.getTypeObject(I).getAttrs(), Kind)) return true; } // Finally, check attributes on the decl itself. return hasParsedAttr(S, PD.getAttributes(), Kind); } /// Adjust the \c DeclContext for a function or variable that might be a /// function-local external declaration. bool Sema::adjustContextForLocalExternDecl(DeclContext *&DC) { if (!DC->isFunctionOrMethod()) return false; // If this is a local extern function or variable declared within a function // template, don't add it into the enclosing namespace scope until it is // instantiated; it might have a dependent type right now. if (DC->isDependentContext()) return true; // C++11 [basic.link]p7: // When a block scope declaration of an entity with linkage is not found to // refer to some other declaration, then that entity is a member of the // innermost enclosing namespace. // // Per C++11 [namespace.def]p6, the innermost enclosing namespace is a // semantically-enclosing namespace, not a lexically-enclosing one. while (!DC->isFileContext() && !isa(DC)) DC = DC->getParent(); return true; } NamedDecl * Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); // dllimport globals without explicit storage class are treated as extern. We // have to change the storage class this early to get the right DeclContext. if (SC == SC_None && !DC->isRecord() && hasParsedAttr(S, D, AttributeList::AT_DLLImport) && !hasParsedAttr(S, D, AttributeList::AT_DLLExport)) SC = SC_Extern; DeclContext *OriginalDC = DC; bool IsLocalExternDecl = SC == SC_Extern && adjustContextForLocalExternDecl(DC); if (getLangOpts().OpenCL) { // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. QualType NR = R; while (NR->isPointerType()) { if (NR->isFunctionPointerType()) { Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer_variable); D.setInvalidType(); break; } NR = NR->getPointeeType(); } if (!getOpenCLOptions().cl_khr_fp16) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). if (Context.getBaseElementType(R)->isHalfType()) { Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; D.setInvalidType(); } } } if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); D.setInvalidType(); SC = SC_None; } if (getLangOpts().CPlusPlus11 && SCSpec == DeclSpec::SCS_register && !D.getAsmLabel() && !getSourceManager().isInSystemMacro( D.getDeclSpec().getStorageClassSpecLoc())) { // In C++11, the 'register' storage class specifier is deprecated. // Suppress the warning in system macros, it's used in macros in some // popular C system headers, such as in glibc's htonl() macro. Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::warn_deprecated_register) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) << Name; return nullptr; } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (!DC->isRecord() && S->getFnParent() == nullptr) { // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. // Global Register+Asm is a GNU extension we support. if (SC == SC_Auto || (SC == SC_Register && !D.getAsmLabel())) { Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); D.setInvalidType(); } } if (getLangOpts().OpenCL) { // Set up the special work-group-local storage class for variables in the // OpenCL __local address space. if (R.getAddressSpace() == LangAS::opencl_local) { SC = SC_OpenCLWorkGroupLocal; } // OpenCL v1.2 s6.9.b p4: // The sampler type cannot be used with the __local and __global address // space qualifiers. if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local || R.getAddressSpace() == LangAS::opencl_global)) { Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); } // OpenCL 1.2 spec, p6.9 r: // The event type cannot be used to declare a program scope variable. // The event type cannot be used with the __local, __constant and __global // address space qualifiers. if (R->isEventT()) { if (S->getParent() == nullptr) { Diag(D.getLocStart(), diag::err_event_t_global_var); D.setInvalidType(); } if (R.getAddressSpace()) { Diag(D.getLocStart(), diag::err_event_t_addr_space_qual); D.setInvalidType(); } } } bool IsExplicitSpecialization = false; bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; bool IsVariableTemplate = false; VarDecl *NewVD = nullptr; VarTemplateDecl *NewTemplate = nullptr; TemplateParameterList *TemplateParams = nullptr; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); if (D.isInvalidType()) NewVD->setInvalidDecl(); } else { bool Invalid = false; if (DC->isRecord() && !CurContext->isRecord()) { // This is an out-of-line definition of a static data member. switch (SC) { case SC_None: break; case SC_Static: Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); break; case SC_Auto: case SC_Register: case SC_Extern: // [dcl.stc] p2: The auto or register specifiers shall be applied only // to names of variables declared in a block or to function parameters. // [dcl.stc] p6: The extern specifier cannot be used in the declaration // of class members Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_storage_class_for_static_member) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); break; case SC_PrivateExtern: llvm_unreachable("C storage class in c++!"); case SC_OpenCLWorkGroupLocal: llvm_unreachable("OpenCL storage class in c++!"); } } if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast(DC)) { if (RD->isLocalClass()) Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) << Name << RD->getDeclName(); // C++98 [class.union]p1: If a union contains a static data member, // the program is ill-formed. C++11 drops this restriction. if (RD->isUnion()) Diag(D.getIdentifierLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_static_data_member_in_union : diag::ext_static_data_member_in_union) << Name; // We conservatively disallow static data members in anonymous structs. else if (!RD->getDeclName()) Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_anon_struct) << Name << RD->isUnion(); } } // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), D.getName().getKind() == UnqualifiedId::IK_TemplateId ? D.getName().TemplateId : nullptr, TemplateParamLists, /*never a friend*/ false, IsExplicitSpecialization, Invalid); if (TemplateParams) { if (!TemplateParams->size() && D.getName().getKind() != UnqualifiedId::IK_TemplateId) { // There is an extraneous 'template<>' for this variable. Complain // about it, but allow the declaration of the variable. Diag(TemplateParams->getTemplateLoc(), diag::err_template_variable_noparams) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); TemplateParams = nullptr; } else { if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { // This is an explicit specialization or a partial specialization. // FIXME: Check that we can declare a specialization here. IsVariableTemplateSpecialization = true; IsPartialSpecialization = TemplateParams->size() > 0; } else { // if (TemplateParams->size() > 0) // This is a template declaration. IsVariableTemplate = true; // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) return nullptr; // Only C++1y supports variable templates (N3651). Diag(D.getIdentifierLoc(), getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_variable_template : diag::ext_variable_template); } } } else { assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId && "should have a 'template<>' for this decl"); } if (IsVariableTemplateSpecialization) { SourceLocation TemplateKWLoc = TemplateParamLists.size() > 0 ? TemplateParamLists[0]->getTemplateLoc() : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, TemplateKWLoc, TemplateParams, SC, IsPartialSpecialization); if (Res.isInvalid()) return nullptr; NewVD = cast(Res.get()); AddToScope = false; } else NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); // If this is supposed to be a variable template, create it as such. if (IsVariableTemplate) { NewTemplate = VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, TemplateParams, NewVD); NewVD->setDescribedVarTemplate(NewTemplate); } // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) { NewVD->setInvalidDecl(); if (NewTemplate) NewTemplate->setInvalidDecl(); } SetNestedNameSpecifier(NewVD, D); // If we have any template parameter lists that don't directly belong to // the variable (matching the scope specifier), store them. unsigned VDTemplateParamLists = TemplateParams ? 1 : 0; if (TemplateParamLists.size() > VDTemplateParamLists) NewVD->setTemplateParameterListsInfo( Context, TemplateParamLists.size() - VDTemplateParamLists, TemplateParamLists.data()); if (D.getDeclSpec().isConstexprSpecified()) NewVD->setConstexpr(true); } // Set the lexical context. If the declarator has a C++ scope specifier, the // lexical context will be different from the semantic context. NewVD->setLexicalDeclContext(CurContext); if (NewTemplate) NewTemplate->setLexicalDeclContext(CurContext); if (IsLocalExternDecl) NewVD->setLocalExternDecl(); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { // C++11 [dcl.stc]p4: // When thread_local is applied to a variable of block scope the // storage-class-specifier static is implied if it does not appear // explicitly. // Core issue: 'static' is not implied if the variable is declared // 'extern'. if (NewVD->hasLocalStorage() && (SCSpec != DeclSpec::SCS_unspecified || TSCS != DeclSpec::TSCS_thread_local || !DC->isFunctionOrMethod())) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); else NewVD->setTSCSpec(TSCS); } // C99 6.7.4p3 // An inline definition of a function with external linkage shall // not contain a definition of a modifiable object with static or // thread storage duration... // We only apply this when the function is required to be defined // elsewhere, i.e. when the function is not 'extern inline'. Note // that a local variable with thread storage duration still has to // be marked 'static'. Also note that it's possible to get these // semantics in C++ using __attribute__((gnu_inline)). if (SC == SC_Static && S->getFnParent() != nullptr && !NewVD->getType().isConstQualified()) { FunctionDecl *CurFD = getCurFunctionDecl(); if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::warn_static_local_in_extern_inline); MaybeSuggestAddingStaticToDecl(CurFD); } } if (D.getDeclSpec().isModulePrivateSpecified()) { if (IsVariableTemplateSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << (IsPartialSpecialization ? 1 : 0) << FixItHint::CreateRemoval( D.getDeclSpec().getModulePrivateSpecLoc()); else if (IsExplicitSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else if (NewVD->hasLocalStorage()) Diag(NewVD->getLocation(), diag::err_module_private_local) << 0 << NewVD->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else { NewVD->setModulePrivate(); if (NewTemplate) NewTemplate->setModulePrivate(); } } // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); if (getLangOpts().CUDA) { // CUDA B.2.5: "__shared__ and __constant__ variables have implied static // storage [duration]." if (SC == SC_None && S->getFnParent() != nullptr && (NewVD->hasAttr() || NewVD->hasAttr())) { NewVD->setStorageClass(SC_Static); } } // Ensure that dllimport globals without explicit storage class are treated as // extern. The storage class is set above using parsed attributes. Now we can // check the VarDecl itself. assert(!NewVD->hasAttr() || NewVD->getAttr()->isInherited() || NewVD->isStaticDataMember() || NewVD->getStorageClass() != SC_None); // In auto-retain/release, infer strong retension for variables of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*)D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); StringRef Label = SE->getString(); if (S->getFnParent() != nullptr) { switch (SC) { case SC_None: case SC_Auto: Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; break; case SC_Register: // Local Named register if (!Context.getTargetInfo().isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; break; case SC_Static: case SC_Extern: case SC_PrivateExtern: case SC_OpenCLWorkGroupLocal: break; } } else if (SC == SC_Register) { // Global Named register if (!Context.getTargetInfo().isValidGCCRegisterName(Label)) Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; if (!R->isIntegralType(Context) && !R->isPointerType()) { Diag(D.getLocStart(), diag::err_asm_bad_register_type); NewVD->setInvalidDecl(true); } } NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, Label, 0)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { NewVD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } } // Diagnose shadowed variables before filtering for scope. if (D.getCXXScopeSpec().isEmpty()) CheckShadow(S, NewVD, Previous); // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewVD), D.getCXXScopeSpec().isNotEmpty() || IsExplicitSpecialization || IsVariableTemplateSpecialization); // Check whether the previous declaration is in the same block scope. This // affects whether we merge types with it, per C++11 [dcl.array]p3. if (getLangOpts().CPlusPlus && NewVD->isLocalVarDecl() && NewVD->hasExternalStorage()) NewVD->setPreviousDeclInSameBlockScope( Previous.isSingleResult() && !Previous.isShadowed() && isDeclInScope(Previous.getFoundDecl(), OriginalDC, S, false)); if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { // If this is an explicit specialization of a static data member, check it. if (IsExplicitSpecialization && !NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); // Merge the decl with the existing one if appropriate. if (!Previous.empty()) { if (Previous.isSingleResult() && isa(Previous.getFoundDecl()) && D.getCXXScopeSpec().isSet()) { // The user tried to define a non-static data member // out-of-line (C++ [dcl.meaning]p1). Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) << D.getCXXScopeSpec().getRange(); Previous.clear(); NewVD->setInvalidDecl(); } } else if (D.getCXXScopeSpec().isSet()) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_no_member) << Name << computeDeclContext(D.getCXXScopeSpec(), true) << D.getCXXScopeSpec().getRange(); NewVD->setInvalidDecl(); } if (!IsVariableTemplateSpecialization) D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() ? NewVD->getPreviousDecl()->getDescribedVarTemplate() : nullptr; // Check the template parameter list of this declaration, possibly // merging in the template parameter list from the previous variable // template declaration. if (CheckTemplateParameterList( TemplateParams, PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() : nullptr, (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && DC->isDependentContext()) ? TPC_ClassTemplateMember : TPC_VarTemplate)) NewVD->setInvalidDecl(); // If we are providing an explicit specialization of a static variable // template, make a note of that. if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate()) PrevVarTemplate->setMemberSpecialization(); } } ProcessPragmaWeak(S, NewVD); // If this is the first declaration of an extern C variable, update // the map of such variables. if (NewVD->isFirstDecl() && !NewVD->isInvalidDecl() && isIncompleteDeclExternC(*this, NewVD)) RegisterLocallyScopedExternCDecl(NewVD, S); if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(NewVD->getDeclContext(), ManglingContextDecl)) { Context.setManglingNumber( NewVD, MCtx->getManglingNumber(NewVD, S->getMSLocalManglingNumber())); Context.setStaticLocalNumber(NewVD, MCtx->getStaticLocalNumber(NewVD)); } } if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewVD, IsExplicitSpecialization); } if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); ActOnDocumentableDecl(NewTemplate); return NewTemplate; } return NewVD; } /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// /// This method is called whenever a VarDecl is added to a "useful" /// scope. /// /// \param S the scope in which the shadowing name is being declared /// \param R the lookup of the name /// void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.isIgnored(diag::warn_decl_shadow, R.getNameLoc())) return; // Don't diagnose declarations at file scope. if (D->hasGlobalStorage()) return; DeclContext *NewDC = D->getDeclContext(); // Only diagnose if we're shadowing an unambiguous field or variable. if (R.getResultKind() != LookupResult::Found) return; NamedDecl* ShadowedDecl = R.getFoundDecl(); if (!isa(ShadowedDecl) && !isa(ShadowedDecl)) return; // Fields are not shadowed by variables in C++ static methods. if (isa(ShadowedDecl)) if (CXXMethodDecl *MD = dyn_cast(NewDC)) if (MD->isStatic()) return; if (VarDecl *shadowedVar = dyn_cast(ShadowedDecl)) if (shadowedVar->isExternC()) { // For shadowing external vars, make sure that we point to the global // declaration, not a locally scoped extern declaration. for (auto I : shadowedVar->redecls()) if (I->isFileVarDecl()) { ShadowedDecl = I; break; } } DeclContext *OldDC = ShadowedDecl->getDeclContext(); // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. if (!OldDC->isRecord()) return; // TODO: should we warn about static data members shadowing // static data members from base classes? // TODO: don't diagnose for inaccessible shadowed members. // This is hard to do perfectly because we might friend the // shadowing context, but that's just a false negative. } // Determine what kind of declaration we're shadowing. unsigned Kind; if (isa(OldDC)) { if (isa(ShadowedDecl)) Kind = 3; // field else Kind = 2; // static data member } else if (OldDC->isFileContext()) Kind = 1; // global else Kind = 0; // local DeclarationName Name = R.getLookupName(); // Emit warning and note. if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation())) return; LookupResult R(*this, D->getDeclName(), D->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); LookupName(R, S); CheckShadow(S, D, R); } /// Check for conflict between this global or extern "C" declaration and /// previous global or extern "C" declarations. This is only used in C++. template static bool checkGlobalOrExternCConflict( Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) { assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\""); NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName()); if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) { // The common case: this global doesn't conflict with any extern "C" // declaration. return false; } if (Prev) { if (!IsGlobal || isIncompleteDeclExternC(S, ND)) { // Both the old and new declarations have C language linkage. This is a // redeclaration. Previous.clear(); Previous.addDecl(Prev); return true; } // This is a global, non-extern "C" declaration, and there is a previous // non-global extern "C" declaration. Diagnose if this is a variable // declaration. if (!isa(ND)) return false; } else { // The declaration is extern "C". Check for any declaration in the // translation unit which might conflict. if (IsGlobal) { // We have already performed the lookup into the translation unit. IsGlobal = false; for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { if (isa(*I)) { Prev = *I; break; } } } else { DeclContext::lookup_result R = S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName()); for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (isa(*I)) { Prev = *I; break; } // FIXME: If we have any other entity with this name in global scope, // the declaration is ill-formed, but that is a defect: it breaks the // 'stat' hack, for instance. Only variables can have mangled name // clashes with extern "C" declarations, so only they deserve a // diagnostic. } } if (!Prev) return false; } // Use the first declaration's location to ensure we point at something which // is lexically inside an extern "C" linkage-spec. assert(Prev && "should have found a previous declaration to diagnose"); if (FunctionDecl *FD = dyn_cast(Prev)) Prev = FD->getFirstDecl(); else Prev = cast(Prev)->getFirstDecl(); S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict) << IsGlobal << ND; S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict) << IsGlobal; return false; } /// Apply special rules for handling extern "C" declarations. Returns \c true /// if we have found that this is a redeclaration of some prior entity. /// /// Per C++ [dcl.link]p6: /// Two declarations [for a function or variable] with C language linkage /// with the same name that appear in different scopes refer to the same /// [entity]. An entity with C language linkage shall not be declared with /// the same name as an entity in global scope. template static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND, LookupResult &Previous) { if (!S.getLangOpts().CPlusPlus) { // In C, when declaring a global variable, look for a corresponding 'extern' // variable declared in function scope. We don't need this in C++, because // we find local extern decls in the surrounding file-scope DeclContext. if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) { Previous.clear(); Previous.addDecl(Prev); return true; } } return false; } // A declaration in the translation unit can conflict with an extern "C" // declaration. if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous); // An extern "C" declaration can conflict with a declaration in the // translation unit or can be a redeclaration of an extern "C" declaration // in another scope. if (isIncompleteDeclExternC(S,ND)) return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous); // Neither global nor extern "C": nothing to do. return false; } void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return; TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); QualType T = TInfo->getType(); // Defer checking an 'auto' type until its initializer is attached. if (T->isUndeducedType()) return; if (NewVD->hasAttrs()) CheckAlignasUnderalignment(NewVD); if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); T = Context.getObjCObjectPointerType(T); NewVD->setType(T); } // Emit an error if an address space was applied to decl with local storage. // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. // ISO/IEC TR 18037 S5.1.2 if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); return; } // OpenCL v1.2 s6.5 - All program scope variables must be declared in the // __constant address space. if (getLangOpts().OpenCL && NewVD->isFileVarDecl() && T.getAddressSpace() != LangAS::opencl_constant && !T->isSamplerT()){ Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space); NewVD->setInvalidDecl(); return; } // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program // scope. if ((getLangOpts().OpenCLVersion >= 120) && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); return; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() && !NewVD->hasAttr()) { if (getLangOpts().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); else { assert(!getLangOpts().ObjCAutoRefCount); Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); } } bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr() || NewVD->hasAttr()) getCurFunction()->setHasBranchProtectedScope(); if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (!FixedTInfo && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange(); if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) << SizeRange; else if (NewVD->isStaticLocal()) Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage) << SizeRange; else Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; NewVD->setInvalidDecl(); return; } if (!FixedTInfo) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); NewVD->setInvalidDecl(); return; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); NewVD->setType(FixedTInfo->getType()); NewVD->setTypeSourceInfo(FixedTInfo); } if (T->isVoidType()) { // C++98 [dcl.stc]p5: The extern specifier can be applied only to the names // of objects and functions. if (NewVD->isThisDeclarationADefinition() || getLangOpts().CPlusPlus) { Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) << T; NewVD->setInvalidDecl(); return; } } if (!NewVD->hasLocalStorage() && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); NewVD->setInvalidDecl(); return; } if (isVM && NewVD->hasAttr()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); return; } if (NewVD->isConstexpr() && !T->isDependentType() && RequireLiteralType(NewVD->getLocation(), T, diag::err_constexpr_var_non_literal)) { NewVD->setInvalidDecl(); return; } } /// \brief Perform semantic checking on a newly-created variable /// declaration. /// /// This routine performs all of the type-checking required for a /// variable declaration once it has been built. It is used both to /// check variables after they have been parsed and their declarators /// have been translated into a declaration, and to check variables /// that have been instantiated from a template. /// /// Sets NewVD->isInvalidDecl() if an error was encountered. /// /// Returns true if the variable declaration is a redeclaration. bool Sema::CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous) { CheckVariableDeclarationType(NewVD); // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) return false; // If we did not find anything by this name, look for a non-visible // extern "C" declaration with the same name. if (Previous.empty() && checkForConflictWithNonVisibleExternC(*this, NewVD, Previous)) Previous.setShadowed(); // Filter out any non-conflicting previous declarations. filterNonConflictingPreviousDecls(Context, NewVD, Previous); if (!Previous.empty()) { MergeVarDecl(NewVD, Previous); return true; } return false; } /// \brief Data used with FindOverriddenMethod struct FindOverriddenMethodData { Sema *S; CXXMethodDecl *Method; }; /// \brief Member lookup function that determines whether a given C++ /// method overrides a method in a base class, to be used with /// CXXRecordDecl::lookupInBases(). static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *UserData) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); FindOverriddenMethodData *Data = reinterpret_cast(UserData); DeclarationName Name = Data->Method->getDeclName(); // FIXME: Do we care about other names here too? if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // We really want to find the base class destructor here. QualType T = Data->S->Context.getTypeDeclType(BaseRecord); CanQualType CT = Data->S->Context.getCanonicalType(T); Name = Data->S->Context.DeclarationNames.getCXXDestructorName(CT); } for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); Path.Decls = Path.Decls.slice(1)) { NamedDecl *D = Path.Decls.front(); if (CXXMethodDecl *MD = dyn_cast(D)) { if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, false)) return true; } } return false; } namespace { enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; } /// \brief Report an error regarding overriding, along with any relevant /// overriden methods. /// /// \param DiagID the primary error to report. /// \param MD the overriding method. /// \param OEK which overrides to include as notes. static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, OverrideErrorKind OEK = OEK_All) { S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { // This check (& the OEK parameter) could be replaced by a predicate, but // without lambdas that would be overkill. This is still nicer than writing // out the diag loop 3 times. if ((OEK == OEK_All) || (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || (OEK == OEK_Deleted && (*I)->isDeleted())) S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); } } /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { // Look for methods in base classes that this method might override. CXXBasePaths Paths; FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; bool hasDeletedOverridenMethods = false; bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (auto *I : Paths.found_decls()) { if (CXXMethodDecl *OldMD = dyn_cast(I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionAttributes(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { hasDeletedOverridenMethods |= OldMD->isDeleted(); hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } if (hasDeletedOverridenMethods && !MD->isDeleted()) { ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); } if (hasNonDeletedOverridenMethods && MD->isDeleted()) { ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); } return AddedAny; } namespace { // Struct for holding all of the extra arguments needed by // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator. struct ActOnFDArgs { Scope *S; Declarator &D; MultiTemplateParamsArg TemplateParamLists; bool AddToScope; }; } namespace { // Callback to only accept typo corrections that have a non-zero edit distance. // Also only accept corrections that have the same parent decl. class DifferentNameValidatorCCC : public CorrectionCandidateCallback { public: DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD, CXXRecordDecl *Parent) : Context(Context), OriginalFD(TypoFD), ExpectedParent(Parent ? Parent->getCanonicalDecl() : nullptr) {} bool ValidateCandidate(const TypoCorrection &candidate) override { if (candidate.getEditDistance() == 0) return false; SmallVector MismatchedParams; for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(), CDeclEnd = candidate.end(); CDecl != CDeclEnd; ++CDecl) { FunctionDecl *FD = dyn_cast(*CDecl); if (FD && !FD->hasBody() && hasSimilarParameters(Context, FD, OriginalFD, MismatchedParams)) { if (CXXMethodDecl *MD = dyn_cast(FD)) { CXXRecordDecl *Parent = MD->getParent(); if (Parent && Parent->getCanonicalDecl() == ExpectedParent) return true; } else if (!ExpectedParent) { return true; } } } return false; } private: ASTContext &Context; FunctionDecl *OriginalFD; CXXRecordDecl *ExpectedParent; }; } /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid /// function redeclaration, including finding possible similar declarations /// or performing typo correction if there are no previous declarations with /// the same name. /// /// Returns a NamedDecl iff typo correction was performed and substituting in /// the new declaration name does not cause new errors. static NamedDecl *DiagnoseInvalidRedeclaration( Sema &SemaRef, LookupResult &Previous, FunctionDecl *NewFD, ActOnFDArgs &ExtraArgs, bool IsLocalFriend, Scope *S) { DeclarationName Name = NewFD->getDeclName(); DeclContext *NewDC = NewFD->getDeclContext(); SmallVector MismatchedParams; SmallVector, 1> NearMatches; TypoCorrection Correction; bool IsDefinition = ExtraArgs.D.isFunctionDefinition(); unsigned DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend : diag::err_member_decl_does_not_match; LookupResult Prev(SemaRef, Name, NewFD->getLocation(), IsLocalFriend ? Sema::LookupLocalFriendName : Sema::LookupOrdinaryName, Sema::ForRedeclaration); NewFD->setInvalidDecl(); if (IsLocalFriend) SemaRef.LookupName(Prev, S); else SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast(NewFD); if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { FunctionDecl *FD = dyn_cast(*Func); if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { // Add 1 to the index so that 0 can mean the mismatch didn't // involve a parameter unsigned ParamNum = MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; NearMatches.push_back(std::make_pair(FD, ParamNum)); } } // If the qualified name lookup yielded nothing, try typo correction } else if ((Correction = SemaRef.CorrectTypo( Prev.getLookupNameInfo(), Prev.getLookupKind(), S, &ExtraArgs.D.getCXXScopeSpec(), llvm::make_unique( SemaRef.Context, NewFD, MD ? MD->getParent() : nullptr), Sema::CTK_ErrorRecovery, IsLocalFriend ? nullptr : NewDC))) { // Set up everything for the call to ActOnFunctionDeclarator ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); Previous.clear(); Previous.setLookupName(Correction.getCorrection()); for (TypoCorrection::decl_iterator CDecl = Correction.begin(), CDeclEnd = Correction.end(); CDecl != CDeclEnd; ++CDecl) { FunctionDecl *FD = dyn_cast(*CDecl); if (FD && !FD->hasBody() && hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { Previous.addDecl(FD); } } bool wasRedeclaration = ExtraArgs.D.isRedeclaration(); NamedDecl *Result; // Retry building the function declaration with the new previous // declarations, and with errors suppressed. { // Trap errors. Sema::SFINAETrap Trap(SemaRef); // TODO: Refactor ActOnFunctionDeclarator so that we can call only the // pieces need to verify the typo-corrected C++ declaration and hopefully // eliminate the need for the parameter pack ExtraArgs. Result = SemaRef.ActOnFunctionDeclarator( ExtraArgs.S, ExtraArgs.D, Correction.getCorrectionDecl()->getDeclContext(), NewFD->getTypeSourceInfo(), Previous, ExtraArgs.TemplateParamLists, ExtraArgs.AddToScope); if (Trap.hasErrorOccurred()) Result = nullptr; } if (Result) { // Determine which correction we picked. Decl *Canonical = Result->getCanonicalDecl(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) if ((*I)->getCanonicalDecl() == Canonical) Correction.setCorrectionDecl(*I); SemaRef.diagnoseTypo( Correction, SemaRef.PDiag(IsLocalFriend ? diag::err_no_matching_local_friend_suggest : diag::err_member_decl_does_not_match_suggest) << Name << NewDC << IsDefinition); return Result; } // Pretend the typo correction never occurred ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(), ExtraArgs.D.getIdentifierLoc()); ExtraArgs.D.setRedeclaration(wasRedeclaration); Previous.clear(); Previous.setLookupName(Name); } SemaRef.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << IsDefinition << NewFD->getLocation(); bool NewFDisConst = false; if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) NewFDisConst = NewMD->isConst(); for (SmallVectorImpl >::iterator NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); NearMatch != NearMatchEnd; ++NearMatch) { FunctionDecl *FD = NearMatch->first; CXXMethodDecl *MD = dyn_cast(FD); bool FDisConst = MD && MD->isConst(); bool IsMember = MD || !IsLocalFriend; // FIXME: These notes are poorly worded for the local friend case. if (unsigned Idx = NearMatch->second) { ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); SourceLocation Loc = FDParam->getTypeSpecStartLoc(); if (Loc.isInvalid()) Loc = FD->getLocation(); SemaRef.Diag(Loc, IsMember ? diag::note_member_def_close_param_match : diag::note_local_decl_close_param_match) << Idx << FDParam->getType() << NewFD->getParamDecl(Idx - 1)->getType(); } else if (FDisConst != NewFDisConst) { SemaRef.Diag(FD->getLocation(), diag::note_member_def_close_const_match) << NewFDisConst << FD->getSourceRange().getEnd(); } else SemaRef.Diag(FD->getLocation(), IsMember ? diag::note_member_def_close_match : diag::note_local_decl_close_match); } return nullptr; } static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) { switch (D.getDeclSpec().getStorageClassSpec()) { default: llvm_unreachable("Unknown storage class!"); case DeclSpec::SCS_auto: case DeclSpec::SCS_register: case DeclSpec::SCS_mutable: SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_typecheck_sclass_func); D.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; case DeclSpec::SCS_extern: if (D.getDeclSpec().isExternInLinkageSpec()) return SC_None; return SC_Extern; case DeclSpec::SCS_static: { if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier // other than extern // See also (C++ [dcl.stc]p4). SemaRef.Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_block_func); break; } else return SC_Static; } case DeclSpec::SCS_private_extern: return SC_PrivateExtern; } // No explicit storage class has already been returned return SC_None; } static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, DeclContext *DC, QualType &R, TypeSourceInfo *TInfo, StorageClass SC, bool &IsVirtualOkay) { DeclarationNameInfo NameInfo = SemaRef.GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); FunctionDecl *NewFD = nullptr; bool isInline = D.getDeclSpec().isInlineSpecified(); if (!SemaRef.getLangOpts().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other reference // to a type name (which eventually refers to a function type). bool HasPrototype = (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!isa(R.getTypePtr()) && R->isFunctionProtoType()); NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, TInfo, SC, isInline, HasPrototype, false); if (D.isInvalidType()) NewFD->setInvalidDecl(); return NewFD; } bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. if (!DC->isRecord() && SemaRef.RequireNonAbstractType( D.getIdentifierLoc(), R->getAs()->getReturnType(), diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType)) D.setInvalidType(); if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && "Constructors can only be declared in a member context"); R = SemaRef.CheckConstructorDeclarator(D, R, SC); return CXXConstructorDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false, isConstexpr); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = SemaRef.CheckDestructorDeclarator(D, R, SC); CXXRecordDecl *Record = cast(DC); CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( SemaRef.Context, Record, D.getLocStart(), NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); // If the class is complete, then we now create the implicit exception // specification. If the class is incomplete or dependent, we can't do // it yet. if (SemaRef.getLangOpts().CPlusPlus11 && !Record->isDependentType() && Record->getDefinition() && !Record->isBeingDefined() && R->getAs()->getExceptionSpecType() == EST_None) { SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); } IsVirtualOkay = true; return NewDD; } else { SemaRef.Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); D.setInvalidType(); // Create a FunctionDecl to satisfy the function definition parsing // code path. return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), D.getIdentifierLoc(), Name, R, TInfo, SC, isInline, /*hasPrototype=*/true, isConstexpr); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { SemaRef.Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); return nullptr; } SemaRef.CheckConversionDeclarator(D, R, SC); IsVirtualOkay = true; return CXXConversionDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, isInline, isExplicit, isConstexpr, SourceLocation()); } else if (DC->isRecord()) { // If the name of the function is the same as the name of the record, // then this must be an invalid constructor that has a return type. // (The parser checks for a return type and makes the declarator a // constructor if it has no return type). if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo() == cast(DC)->getIdentifier()){ SemaRef.Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); return nullptr; } // This is a C++ method declaration. CXXMethodDecl *Ret = CXXMethodDecl::Create(SemaRef.Context, cast(DC), D.getLocStart(), NameInfo, R, TInfo, SC, isInline, isConstexpr, SourceLocation()); IsVirtualOkay = !Ret->isStatic(); return Ret; } else { bool isFriend = SemaRef.getLangOpts().CPlusPlus && D.getDeclSpec().isFriendSpecified(); if (!isFriend && SemaRef.CurContext->isRecord()) return nullptr; // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), return FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, TInfo, SC, isInline, true/*HasPrototype*/, isConstexpr); } } enum OpenCLParamType { ValidKernelParam, PtrPtrKernelParam, PtrKernelParam, PrivatePtrKernelParam, InvalidKernelParam, RecordKernelParam }; static OpenCLParamType getOpenCLKernelParameterType(QualType PT) { if (PT->isPointerType()) { QualType PointeeType = PT->getPointeeType(); if (PointeeType->isPointerType()) return PtrPtrKernelParam; return PointeeType.getAddressSpace() == 0 ? PrivatePtrKernelParam : PtrKernelParam; } // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can // be used as builtin types. if (PT->isImageType()) return PtrKernelParam; if (PT->isBooleanType()) return InvalidKernelParam; if (PT->isEventT()) return InvalidKernelParam; if (PT->isHalfType()) return InvalidKernelParam; if (PT->isRecordType()) return RecordKernelParam; return ValidKernelParam; } static void checkIsValidOpenCLKernelParameter( Sema &S, Declarator &D, ParmVarDecl *Param, llvm::SmallPtrSetImpl &ValidTypes) { QualType PT = Param->getType(); // Cache the valid types we encounter to avoid rechecking structs that are // used again if (ValidTypes.count(PT.getTypePtr())) return; switch (getOpenCLKernelParameterType(PT)) { case PtrPtrKernelParam: // OpenCL v1.2 s6.9.a: // A kernel function argument cannot be declared as a // pointer to a pointer type. S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param); D.setInvalidType(); return; case PrivatePtrKernelParam: // OpenCL v1.2 s6.9.a: // A kernel function argument cannot be declared as a // pointer to the private address space. S.Diag(Param->getLocation(), diag::err_opencl_private_ptr_kernel_param); D.setInvalidType(); return; // OpenCL v1.2 s6.9.k: // Arguments to kernel functions in a program cannot be declared with the // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and // uintptr_t or a struct and/or union that contain fields declared to be // one of these built-in scalar types. case InvalidKernelParam: // OpenCL v1.2 s6.8 n: // A kernel function argument cannot be declared // of event_t type. S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; D.setInvalidType(); return; case PtrKernelParam: case ValidKernelParam: ValidTypes.insert(PT.getTypePtr()); return; case RecordKernelParam: break; } // Track nested structs we will inspect SmallVector VisitStack; // Track where we are in the nested structs. Items will migrate from // VisitStack to HistoryStack as we do the DFS for bad field. SmallVector HistoryStack; HistoryStack.push_back(nullptr); const RecordDecl *PD = PT->castAs()->getDecl(); VisitStack.push_back(PD); assert(VisitStack.back() && "First decl null?"); do { const Decl *Next = VisitStack.pop_back_val(); if (!Next) { assert(!HistoryStack.empty()); // Found a marker, we have gone up a level if (const FieldDecl *Hist = HistoryStack.pop_back_val()) ValidTypes.insert(Hist->getType().getTypePtr()); continue; } // Adds everything except the original parameter declaration (which is not a // field itself) to the history stack. const RecordDecl *RD; if (const FieldDecl *Field = dyn_cast(Next)) { HistoryStack.push_back(Field); RD = Field->getType()->castAs()->getDecl(); } else { RD = cast(Next); } // Add a null marker so we know when we've gone back up a level VisitStack.push_back(nullptr); for (const auto *FD : RD->fields()) { QualType QT = FD->getType(); if (ValidTypes.count(QT.getTypePtr())) continue; OpenCLParamType ParamType = getOpenCLKernelParameterType(QT); if (ParamType == ValidKernelParam) continue; if (ParamType == RecordKernelParam) { VisitStack.push_back(FD); continue; } // OpenCL v1.2 s6.9.p: // Arguments to kernel functions that are declared to be a struct or union // do not allow OpenCL objects to be passed as elements of the struct or // union. if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam || ParamType == PrivatePtrKernelParam) { S.Diag(Param->getLocation(), diag::err_record_with_pointers_kernel_param) << PT->isUnionType() << PT; } else { S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; } S.Diag(PD->getLocation(), diag::note_within_field_of_type) << PD->getDeclName(); // We have an error, now let's go back up through history and show where // the offending field came from for (ArrayRef::const_iterator I = HistoryStack.begin() + 1, E = HistoryStack.end(); I != E; ++I) { const FieldDecl *OuterField = *I; S.Diag(OuterField->getLocation(), diag::note_within_field_of_type) << OuterField->getType(); } S.Diag(FD->getLocation(), diag::note_illegal_field_declared_here) << QT->isPointerType() << QT; D.setInvalidType(); return; } } while (!VisitStack.empty()); } NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope) { QualType R = TInfo->getType(); assert(R.getTypePtr()->isFunctionType()); // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); StorageClass SC = getFunctionStorageClass(*this, D); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); if (D.isFirstDeclarationOfMember()) adjustMemberFunctionCC(R, D.isStaticMember()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; bool isExplicitSpecialization = false; bool isFunctionTemplateSpecialization = false; bool isDependentClassScopeExplicitSpecialization = false; bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; bool isVirtualOkay = false; DeclContext *OriginalDC = DC; bool IsLocalExternDecl = adjustContextForLocalExternDecl(DC); FunctionDecl *NewFD = CreateNewFunctionDecl(*this, D, DC, R, TInfo, SC, isVirtualOkay); if (!NewFD) return nullptr; if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer()) NewFD->setTopLevelDeclInObjCContainer(); // Set the lexical context. If this is a function-scope declaration, or has a // C++ scope specifier, or is the object of a friend declaration, the lexical // context will be different from the semantic context. NewFD->setLexicalDeclContext(CurContext); if (IsLocalExternDecl) NewFD->setLocalExternDecl(); if (getLangOpts().CPlusPlus) { bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); bool isConstexpr = D.getDeclSpec().isConstexprSpecified(); isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { // C++ [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. NewFD->setImplicitlyInline(); } // If this is a method defined in an __interface, and is not a constructor // or an overloaded operator, then set the pure flag (isVirtual will already // return true). if (const CXXRecordDecl *Parent = dyn_cast(NewFD->getDeclContext())) { if (Parent->isInterface() && cast(NewFD)->isUserProvided()) NewFD->setPure(true); } SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; if (D.isInvalidType()) NewFD->setInvalidDecl(); // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), D.getName().getKind() == UnqualifiedId::IK_TemplateId ? D.getName().TemplateId : nullptr, TemplateParamLists, isFriend, isExplicitSpecialization, Invalid)) { if (TemplateParams->size() > 0) { // This is a function template // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParams)) return nullptr; // A destructor cannot be a template. if (Name.getNameKind() == DeclarationName::CXXDestructorName) { Diag(NewFD->getLocation(), diag::err_destructor_template); return nullptr; } // If we're adding a template to a dependent context, we may need to // rebuilding some of the types used within the template parameter list, // now that we know what the current instantiation is. if (DC->isDependentContext()) { ContextRAII SavedContext(*this, DC); if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), Name, TemplateParams, NewFD); FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size() - 1, TemplateParamLists.data()); } } else { // This is a function template specialization. isFunctionTemplateSpecialization = true; // For source fidelity, store all the template param lists. if (TemplateParamLists.size() > 0) NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.data()); // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend) { // We want to remove the "template<>", found here. SourceRange RemoveRange = TemplateParams->getSourceRange(); // If we remove the template<> and the name is not a // template-id, we're actually silently creating a problem: // the friend declaration will refer to an untemplated decl, // and clearly the user wants a template specialization. So // we need to insert '<>' after the name. SourceLocation InsertLoc; if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { InsertLoc = D.getName().getSourceRange().getEnd(); InsertLoc = getLocForEndOfToken(InsertLoc); } Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) << Name << RemoveRange << FixItHint::CreateRemoval(RemoveRange) << FixItHint::CreateInsertion(InsertLoc, "<>"); } } } else { // All template param lists were matched against the scope specifier: // this is NOT (an explicit specialization of) a template. if (TemplateParamLists.size() > 0) // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.data()); } if (Invalid) { NewFD->setInvalidDecl(); if (FunctionTemplate) FunctionTemplate->setInvalidDecl(); } // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a // member-specification of a class declaration; see 10.3. // if (isVirtual && !NewFD->isInvalidDecl()) { if (!isVirtualOkay) { Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_non_function); } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else if (NewFD->getDescribedFunctionTemplate()) { // C++ [temp.mem]p3: // A member function template shall not be virtual. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_member_function_template) << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. NewFD->setVirtualAsWritten(true); } if (getLangOpts().CPlusPlus14 && NewFD->getReturnType()->isUndeducedType()) Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } if (getLangOpts().CPlusPlus14 && (NewFD->isDependentContext() || (isFriend && CurContext->isDependentContext())) && NewFD->getReturnType()->isUndeducedType()) { // If the function template is referenced directly (for instance, as a // member of the current instantiation), pretend it has a dependent type. // This is not really justified by the standard, but is the only sane // thing to do. // FIXME: For a friend function, we have not marked the function as being // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs(); QualType Result = SubstAutoType(FPT->getReturnType(), Context.DependentTy); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } // C++ [dcl.fct.spec]p3: // The inline specifier shall not appear on a block scope function // declaration. if (isInline && !NewFD->isInvalidDecl()) { if (CurContext->isFunctionOrMethod()) { // 'inline' is not allowed on block scope function declaration. Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_declaration_block_scope) << Name << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } } // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; // see 12.3.1 and 12.3.2. if (isExplicit && !NewFD->isInvalidDecl()) { if (!CurContext->isRecord()) { // 'explicit' was specified outside of the class. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } else if (!isa(NewFD) && !isa(NewFD)) { // 'explicit' was specified on a function that wasn't a constructor // or conversion function. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_ctor_or_conv_function) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } } if (isConstexpr) { // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors // are implicitly inline. NewFD->setImplicitlyInline(); // C++11 [dcl.constexpr]p3: functions declared constexpr are required to // be either constructors or to return a literal type. Therefore, // destructors cannot be declared constexpr. if (isa(NewFD)) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor); } // If __module_private__ was specified, mark the function accordingly. if (D.getDeclSpec().isModulePrivateSpecified()) { if (isFunctionTemplateSpecialization) { SourceLocation ModulePrivateLoc = D.getDeclSpec().getModulePrivateSpecLoc(); Diag(ModulePrivateLoc, diag::err_module_private_specialization) << 0 << FixItHint::CreateRemoval(ModulePrivateLoc); } else { NewFD->setModulePrivate(); if (FunctionTemplate) FunctionTemplate->setModulePrivate(); } } if (isFriend) { if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(); FunctionTemplate->setAccess(AS_public); } NewFD->setObjectOfFriendDecl(); NewFD->setAccess(AS_public); } // If a function is defined as defaulted or deleted, mark it as such now. // FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function // definition kind to FDK_Definition. switch (D.getFunctionDefinitionKind()) { case FDK_Declaration: case FDK_Definition: break; case FDK_Defaulted: NewFD->setDefaulted(); break; case FDK_Deleted: NewFD->setDeletedAsWritten(); break; } if (isa(NewFD) && DC == CurContext && D.isFunctionDefinition()) { // C++ [class.mfct]p2: // A member function may be defined (8.4) in its class definition, in // which case it is an inline member function (7.1.2) NewFD->setImplicitlyInline(); } if (SC == SC_Static && isa(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: // A data or function member of a class may be declared static // in a class definition, in which case it is a static member of // the class. // Complain about the 'static' specifier if it's on an out-of-line // member function definition. Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } // C++11 [except.spec]p15: // A deallocation function with no exception-specification is treated // as if it were specified with noexcept(true). const FunctionProtoType *FPT = R->getAs(); if ((Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) && getLangOpts().CPlusPlus11 && FPT && !FPT->hasExceptionSpec()) NewFD->setType(Context.getFunctionType( FPT->getReturnType(), FPT->getParamTypes(), FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); } // Filter out previous declarations that don't match the scope. FilterLookupForScope(Previous, OriginalDC, S, shouldConsiderLinkage(NewFD), D.getCXXScopeSpec().isNotEmpty() || isExplicitSpecialization || isFunctionTemplateSpecialization); // Handle GNU asm-label extension (encoded as an attribute). if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, SE->getString(), 0)); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); if (I != ExtnameUndeclaredIdentifiers.end()) { NewFD->addAttr(I->second); ExtnameUndeclaredIdentifiers.erase(I); } } // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. SmallVector Params; if (D.isFunctionDeclarator()) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a // single void argument. // We let through "const void" here because Sema::GetTypeForDeclarator // already checks for that case. if (FTIHasNonVoidParameters(FTI) && FTI.Params[0].Param) { for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) { ParmVarDecl *Param = cast(FTI.Params[i].Param); assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); if (Param->isInvalidDecl()) NewFD->setInvalidDecl(); } } } else if (const FunctionProtoType *FT = R->getAs()) { // When we're declaring a function with a typedef, typeof, etc as in the // following example, we'll need to synthesize (unnamed) // parameters for use in the declaration. // // @code // typedef void fn(int); // fn f; // @endcode // Synthesize a parameter for each argument type. for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), AI); Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } } else { assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && "Should not need args for typedef of non-prototype fn"); } // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params); // Find all anonymous symbols defined during the declaration of this function // and add to NewFD. This lets us track decls such 'enum Y' in: // // void f(enum Y {AA} x) {} // // which would otherwise incorrectly end up in the translation unit scope. NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope); DeclsInPrototypeScope.clear(); if (D.getDeclSpec().isNoreturnSpecified()) NewFD->addAttr( ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), Context, 0)); // Functions returning a variably modified type violate C99 6.7.5.2p2 // because all functions have linkage. if (!NewFD->isInvalidDecl() && NewFD->getReturnType()->isVariablyModifiedType()) { Diag(NewFD->getLocation(), diag::err_vm_func_decl); NewFD->setInvalidDecl(); } if (D.isFunctionDefinition() && CodeSegStack.CurrentValue && !NewFD->hasAttr()) { NewFD->addAttr( SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, CodeSegStack.CurrentValue->getString(), CodeSegStack.CurrentPragmaLocation)); if (UnifySection(CodeSegStack.CurrentValue->getString(), ASTContext::PSF_Implicit | ASTContext::PSF_Execute | ASTContext::PSF_Read, NewFD)) NewFD->dropAttr(); } // Handle attributes. ProcessDeclAttributes(S, NewFD, D); QualType RetType = NewFD->getReturnType(); const CXXRecordDecl *Ret = RetType->isRecordType() ? RetType->getAsCXXRecordDecl() : RetType->getPointeeCXXRecordDecl(); if (!NewFD->isInvalidDecl() && !NewFD->hasAttr() && Ret && Ret->hasAttr()) { const CXXMethodDecl *MD = dyn_cast(NewFD); // Attach WarnUnusedResult to functions returning types with that attribute. // Don't apply the attribute to that type's own non-static member functions // (to avoid warning on things like assignment operators) if (!MD || MD->getParent() != Ret) NewFD->addAttr(WarnUnusedResultAttr::CreateImplicit(Context)); } if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return // type declaration will generate a compilation error. unsigned AddressSpace = RetType.getAddressSpace(); if (AddressSpace == LangAS::opencl_local || AddressSpace == LangAS::opencl_global || AddressSpace == LangAS::opencl_constant) { Diag(NewFD->getLocation(), diag::err_opencl_return_value_with_address_space); NewFD->setInvalidDecl(); } } if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. bool isExplicitSpecialization=false; if (!NewFD->isInvalidDecl() && NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); else if (!Previous.empty()) // Make graceful recovery from an invalid redeclaration. D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); // Diagnose no-prototype function declarations with calling conventions that // don't support variadic calls. Only do this in C and do it after merging // possibly prototyped redeclarations. const FunctionType *FT = NewFD->getType()->castAs(); if (isa(FT) && !D.isFunctionDefinition()) { CallingConv CC = FT->getExtInfo().getCC(); if (!supportsVariadicCall(CC)) { // Windows system headers sometimes accidentally use stdcall without // (void) parameters, so we relax this to a warning. int DiagID = CC == CC_X86StdCall ? diag::warn_cconv_knr : diag::err_cconv_knr; Diag(NewFD->getLocation(), DiagID) << FunctionType::getNameForCallConv(CC); } } } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. // // N.B. We diagnose declarations instead of definitions per LWG issue 2340. // // Suppress the diagnostic if the function is __attribute__((used)), since // that forces an external definition to be emitted. if (D.getDeclSpec().isInlineSpecified() && NewFD->isReplaceableGlobalAllocationFunction() && !NewFD->hasAttr()) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::ext_operator_new_delete_declared_inline) << NewFD->getDeclName(); // If the declarator is a template-id, translate the parser's template // argument list into our AST format. if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); HasExplicitTemplateArgs = true; if (NewFD->isInvalidDecl()) { HasExplicitTemplateArgs = false; } else if (FunctionTemplate) { // Function template with explicit template arguments. Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); HasExplicitTemplateArgs = false; } else { assert((isFunctionTemplateSpecialization || D.getDeclSpec().isFriendSpecified()) && "should have a 'template<>' for this decl"); // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } } else if (isFriend && isFunctionTemplateSpecialization) { // This combination is only possible in a recovery case; the user // wrote something like: // template <> friend void foo(int); // which we're recovering from as if the user had written: // friend void foo<>(int); // Go ahead and fake up a template id. HasExplicitTemplateArgs = true; TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); } // If it's a friend (and only if it's a friend), it's possible // that either the specialized function type or the specialized // template is dependent, and therefore matching will fail. In // this case, don't check the specialization yet. bool InstantiationDependent = false; if (isFunctionTemplateSpecialization && isFriend && (NewFD->getType()->isDependentType() || DC->isDependentContext() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs.getArgumentArray(), TemplateArgs.size(), InstantiationDependent))) { assert(HasExplicitTemplateArgs && "friend function specialization without template args"); if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, Previous)) NewFD->setInvalidDecl(); } else if (isFunctionTemplateSpecialization) { if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? diag::ext_function_specialization_in_class : diag::err_function_specialization_in_class) << NewFD->getDeclName(); } else if (CheckFunctionTemplateSpecialization(NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), Previous)) NewFD->setInvalidDecl(); // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) FunctionTemplateSpecializationInfo *Info = NewFD->getTemplateSpecializationInfo(); if (Info && SC != SC_None) { if (SC != Info->getTemplate()->getTemplatedDecl()->getStorageClass()) Diag(NewFD->getLocation(), diag::err_explicit_specialization_inconsistent_storage_class) << SC << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); else Diag(NewFD->getLocation(), diag::ext_explicit_specialization_storage_class) << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); } } else if (isExplicitSpecialization && isa(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); } // Perform semantic checking on the function declaration. if (!isDependentClassScopeExplicitSpecialization) { if (!NewFD->isInvalidDecl() && NewFD->isMain()) CheckMain(NewFD, D.getDeclSpec()); if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) CheckMSVCRTEntryPoint(NewFD); if (!NewFD->isInvalidDecl()) D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); } assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); NamedDecl *PrincipalDecl = (FunctionTemplate ? cast(FunctionTemplate) : NewFD); if (isFriend && D.isRedeclaration()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDecl()->getAccess(); NewFD->setAccess(Access); if (FunctionTemplate) FunctionTemplate->setAccess(Access); } if (NewFD->isOverloadedOperator() && !DC->isRecord() && PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDecl(); CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), PrevTemplate ? PrevTemplate->getTemplateParameters() : nullptr, D.getDeclSpec().isFriendSpecified() ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition : TPC_FriendFunctionTemplate) : (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && DC->isDependentContext()) ? TPC_ClassTemplateMember : TPC_FunctionTemplate); } if (NewFD->isInvalidDecl()) { // Ignore all the rest of this. } else if (!D.isRedeclaration()) { struct ActOnFDArgs ExtraArgs = { S, D, TemplateParamLists, AddToScope }; // Fake up an access specifier if it's supposed to be a class member. if (isa(NewFD->getDeclContext())) NewFD->setAccess(AS_public); // Qualified decls generally require a previous declaration. if (D.getCXXScopeSpec().isSet()) { // ...with the major exception of templated-scope or // dependent-scope friend declarations. // TODO: we currently also suppress this check in dependent // contexts because (1) the parameter depth will be off when // matching friend templates and (2) we might actually be // selecting a friend based on a dependent factor. But there // are situations where these conditions don't apply and we // can actually do this check immediately. if (isFriend && (TemplateParamLists.size() || D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { // ignore these } else { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, // C++ [namespace.memdef]p2). For example: // // class X { // void f() const; // }; // // void X::f() { } // ill-formed // // Complain about this problem, and attempt to suggest close // matches (e.g., those that differ only in cv-qualifiers and // whether the parameter types are references). if (NamedDecl *Result = DiagnoseInvalidRedeclaration( *this, Previous, NewFD, ExtraArgs, false, nullptr)) { AddToScope = ExtraArgs.AddToScope; return Result; } } // Unqualified local friend declarations are required to resolve // to something. } else if (isFriend && cast(CurContext)->isLocalClass()) { if (NamedDecl *Result = DiagnoseInvalidRedeclaration( *this, Previous, NewFD, ExtraArgs, true, S)) { AddToScope = ExtraArgs.AddToScope; return Result; } } } else if (!D.isFunctionDefinition() && isa(NewFD) && NewFD->isOutOfLine() && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { // An out-of-line member function declaration must also be a // definition (C++ [class.mfct]p2). // Note that this is not the case for explicit specializations of // function templates or member functions of class templates, per // C++ [temp.expl.spec]p2. We also allow these declarations as an // extension for compatibility with old SWIG code which likes to // generate them. Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); } } ProcessPragmaWeak(S, NewFD); checkAttributesAfterMerging(*this, *NewFD); AddKnownFunctionAttributes(NewFD); if (NewFD->hasAttr() && !NewFD->getType()->getAs()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) << NewFD; // Turn this into a variadic function with no parameters. const FunctionType *FT = NewFD->getType()->getAs(); FunctionProtoType::ExtProtoInfo EPI( Context.getDefaultCallingConvention(true, false)); EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI); NewFD->setType(R); } // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this function. if (!DC->isRecord() && NewFD->isExternallyVisible()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider // marking the function. AddCFAuditedAttribute(NewFD); // If this is a function definition, check if we have to apply optnone due to // a pragma. if(D.isFunctionDefinition()) AddRangeBasedOptnone(NewFD); // If this is the first declaration of an extern C variable, update // the map of such variables. if (NewFD->isFirstDecl() && !NewFD->isInvalidDecl() && isIncompleteDeclExternC(*this, NewFD)) RegisterLocallyScopedExternCDecl(NewFD, S); // Set this FunctionDecl's range up to the right paren. NewFD->setRangeEnd(D.getSourceRange().getEnd()); if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast(Previous.getRepresentativeDecl()), NewFD, isExplicitSpecialization || isFunctionTemplateSpecialization); } if (getLangOpts().CPlusPlus) { if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); return FunctionTemplate; } } if (NewFD->hasAttr()) { // OpenCL v1.2 s6.8 static is invalid for kernel functions. if ((getLangOpts().OpenCLVersion >= 120) && (SC == SC_Static)) { Diag(D.getIdentifierLoc(), diag::err_static_kernel); D.setInvalidType(); } // OpenCL v1.2, s6.9 -- Kernels can only have return type void. if (!NewFD->getReturnType()->isVoidType()) { SourceRange RTRange = NewFD->getReturnTypeSourceRange(); Diag(D.getIdentifierLoc(), diag::err_expected_kernel_void_return_type) << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void") : FixItHint()); D.setInvalidType(); } llvm::SmallPtrSet ValidTypes; for (auto Param : NewFD->params()) checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes); } MarkUnusedFileScopedDecl(NewFD); if (getLangOpts().CUDA) if (IdentifierInfo *II = NewFD->getIdentifier()) if (!NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (II->isStr("cudaConfigureCall")) { if (!R->getAs()->getReturnType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return); Context.setcudaConfigureCallDecl(NewFD); } } // Here we have an function template explicit specialization at class scope. // The actually specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( Context, CurContext, SourceLocation(), cast(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); AddToScope = false; } return NewFD; } /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration /// NewFD. This routine performs all semantic checking that does not /// require the actual declarator involved in the declaration, and is /// used both for the declaration of functions as they are parsed /// (called via ActOnDeclarator) and for the declaration of functions /// that have been instantiated via C++ template instantiation (called /// via InstantiateDecl). /// /// \param IsExplicitSpecialization whether this new function declaration is /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. /// /// \returns true if the function declaration is a redeclaration. bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization) { assert(!NewFD->getReturnType()->isVariablyModifiedType() && "Variably modified return types are not handled here"); // Determine whether the type of this function should be merged with // a previous visible declaration. This never happens for functions in C++, // and always happens in C if the previous declaration was visible. bool MergeTypeWithPrevious = !getLangOpts().CPlusPlus && !Previous.isShadowed(); // Filter out any non-conflicting previous declarations. filterNonConflictingPreviousDecls(Context, NewFD, Previous); bool Redeclaration = false; NamedDecl *OldDecl = nullptr; // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. if (!Previous.empty()) { // Determine whether NewFD is an overload of PrevDecl or // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new // function to the scope. if (!AllowOverloadingOfFunction(Previous, Context)) { NamedDecl *Candidate = Previous.getFoundDecl(); if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { Redeclaration = true; OldDecl = Candidate; } } else { switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: Redeclaration = true; break; case Ovl_NonFunction: Redeclaration = true; break; case Ovl_Overload: Redeclaration = false; break; } if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { // If a function name is overloadable in C, then every function // with that name must be marked "overloadable". Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; NamedDecl *OverloadedDecl = nullptr; if (Redeclaration) OverloadedDecl = OldDecl; else if (!Previous.empty()) OverloadedDecl = Previous.getRepresentativeDecl(); if (OverloadedDecl) Diag(OverloadedDecl->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); } } } // Check for a previous extern "C" declaration with this name. if (!Redeclaration && checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) { filterNonConflictingPreviousDecls(Context, NewFD, Previous); if (!Previous.empty()) { // This is an extern "C" declaration with the same name as a previous // declaration, and thus redeclares that entity... Redeclaration = true; OldDecl = Previous.getFoundDecl(); MergeTypeWithPrevious = false; // ... except in the presence of __attribute__((overloadable)). if (OldDecl->hasAttr()) { if (!getLangOpts().CPlusPlus && !NewFD->hasAttr()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; Diag(Previous.getFoundDecl()->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); } if (IsOverload(NewFD, cast(OldDecl), false)) { Redeclaration = false; OldDecl = nullptr; } } } } // C++11 [dcl.constexpr]p8: // A constexpr specifier for a non-static member function that is not // a constructor declares that member function to be const. // // This needs to be delayed until we know whether this is an out-of-line // definition of a static member function. // // This rule is not present in C++1y, so we produce a backwards // compatibility warning whenever it happens in C++11. CXXMethodDecl *MD = dyn_cast(NewFD); if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() && !MD->isStatic() && !isa(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = nullptr; if (OldDecl) OldMD = dyn_cast_or_null(OldDecl->getAsFunction()); if (!OldMD || !OldMD->isStatic()) { const FunctionProtoType *FPT = MD->getType()->castAs(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.TypeQuals |= Qualifiers::Const; MD->setType(Context.getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI)); // Warn that we did this, if we're not performing template instantiation. // In that case, we'll have warned already when the template was defined. if (ActiveTemplateInstantiations.empty()) { SourceLocation AddConstLoc; if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc() .IgnoreParens().getAs()) AddConstLoc = getLocForEndOfToken(FTL.getRParenLoc()); Diag(MD->getLocation(), diag::warn_cxx14_compat_constexpr_not_const) << FixItHint::CreateInsertion(AddConstLoc, " const"); } } } if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious)) { NewFD->setInvalidDecl(); return Redeclaration; } Previous.clear(); Previous.addDecl(OldDecl); if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast(OldDecl)) { NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); if (CXXMethodDecl *Method = dyn_cast(NewTemplateDecl->getTemplatedDecl())) { Method->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } // If this is an explicit specialization of a member that is a function // template, mark it as a member specialization. if (IsExplicitSpecialization && NewTemplateDecl->getInstantiatedFromMemberTemplate()) { NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); } } else { // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(cast(OldDecl)); if (isa(NewFD)) { // A valid redeclaration of a C++ method must be out-of-line, // but (unfortunately) it's not necessarily a definition // because of templates, which means that the previous // declaration is not necessarily from the class definition. // For just setting the access, that doesn't matter. CXXMethodDecl *oldMethod = cast(OldDecl); NewFD->setAccess(oldMethod->getAccess()); // Update the key-function state if necessary for this ABI. if (NewFD->isInlined() && !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { // setNonKeyFunction needs to work with the original // declaration from the class definition, and isVirtual() is // just faster in that case, so map back to that now. oldMethod = cast(oldMethod->getFirstDecl()); if (oldMethod->isVirtual()) { Context.setNonKeyFunction(oldMethod); } } } } } // Semantic checking for this function declaration (in isolation). if (getLangOpts().CPlusPlus) { // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast(NewFD)) { CheckConstructor(Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast(NewFD)) { CXXRecordDecl *Record = Destructor->getParent(); QualType ClassType = Context.getTypeDeclType(Record); // FIXME: Shouldn't we be able to perform this check even when the class // type is dependent? Both gcc and edg can handle that. if (!ClassType->isDependentType()) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); NewFD->setInvalidDecl(); return Redeclaration; } } } else if (CXXConversionDecl *Conversion = dyn_cast(NewFD)) { ActOnConversionDeclarator(Conversion); } // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && !Method->getDescribedFunctionTemplate() && Method->isCanonicalDecl()) { if (AddOverriddenMethods(Method->getParent(), Method)) { // If the function was marked as "static", we have a problem. if (NewFD->getStorageClass() == SC_Static) { ReportOverrides(*this, diag::err_static_overrides_virtual, Method); } } } if (Method->isStatic()) checkThisInStaticMemberFunctionType(Method); } // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) { NewFD->setInvalidDecl(); return Redeclaration; } // Extra checking for C++0x literal operators (C++0x [over.literal]). if (NewFD->getLiteralIdentifier() && CheckLiteralOperatorDeclaration(NewFD)) { NewFD->setInvalidDecl(); return Redeclaration; } // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done // during delayed parsing anyway. if (!CurContext->isRecord()) CheckCXXDefaultArguments(NewFD); // If this function declares a builtin function, check the type of this // declaration against the expected type for the builtin. if (unsigned BuiltinID = NewFD->getBuiltinID()) { ASTContext::GetBuiltinTypeError Error; LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier()); QualType T = Context.GetBuiltinType(BuiltinID, Error); if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) { // The type of this function differs from the type of the builtin, // so forget about the builtin entirely. Context.BuiltinInfo.ForgetBuiltin(BuiltinID, Context.Idents); } } // If this function is declared as being extern "C", then check to see if // the function returns a UDT (class, struct, or union type) that is not C // compatible, and if it does, warn the user. // But, issue any diagnostic on the first declaration only. if (Previous.empty() && NewFD->isExternC()) { QualType R = NewFD->getReturnType(); if (R->isIncompleteType() && !R->isVoidType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete) << NewFD << R; else if (!R.isPODType(Context) && !R->isVoidType() && !R->isObjCObjectPointerType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } } return Redeclaration; } void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // C++11 [basic.start.main]p3: // A program that [...] declares main to be inline, static or // constexpr is ill-formed. // C11 6.7.4p4: In a hosted environment, no function specifier(s) shall // appear in a declaration of main. // static main is not an error under C99, but we should warn about it. // We accept _Noreturn main as an extension. if (FD->getStorageClass() == SC_Static) Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus ? diag::err_static_main : diag::warn_static_main) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); if (FD->isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_main) << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); if (DS.isNoreturnSpecified()) { SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc(); SourceRange NoreturnRange(NoreturnLoc, getLocForEndOfToken(NoreturnLoc)); Diag(NoreturnLoc, diag::ext_noreturn_main); Diag(NoreturnLoc, diag::note_main_remove_noreturn) << FixItHint::CreateRemoval(NoreturnRange); } if (FD->isConstexpr()) { Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main) << FixItHint::CreateRemoval(DS.getConstexprSpecLoc()); FD->setConstexpr(false); } if (getLangOpts().OpenCL) { Diag(FD->getLocation(), diag::err_opencl_no_main) << FD->hasAttr(); FD->setInvalidDecl(); return; } QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType* FT = T->castAs(); if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) { // In C with GNU extensions we allow main() to have non-integer return // type, but we should warn about the extension, and we disable the // implicit-return-zero rule. // GCC in C mode accepts qualified 'int'. if (Context.hasSameUnqualifiedType(FT->getReturnType(), Context.IntTy)) FD->setHasImplicitReturnZero(true); else { Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint); SourceRange RTRange = FD->getReturnTypeSourceRange(); if (RTRange.isValid()) Diag(RTRange.getBegin(), diag::note_main_change_return_type) << FixItHint::CreateReplacement(RTRange, "int"); } } else { // In C and C++, main magically returns 0 if you fall off the end; // set the flag which tells us that. // This is C++ [basic.start.main]p5 and C99 5.1.2.2.3. // All the standards say that main() should return 'int'. if (Context.hasSameType(FT->getReturnType(), Context.IntTy)) FD->setHasImplicitReturnZero(true); else { // Otherwise, this is just a flat-out error. SourceRange RTRange = FD->getReturnTypeSourceRange(); Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint) << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "int") : FixItHint()); FD->setInvalidDecl(true); } } // Treat protoless main() as nullary. if (isa(FT)) return; const FunctionProtoType* FTP = cast(FT); unsigned nparams = FTP->getNumParams(); assert(FD->getNumParams() == nparams); bool HasExtraParameters = (nparams > 3); // Darwin passes an undocumented fourth argument of type char**. If // other platforms start sprouting these, the logic below will start // getting shifty. if (nparams == 4 && Context.getTargetInfo().getTriple().isOSDarwin()) HasExtraParameters = false; if (HasExtraParameters) { Diag(FD->getLocation(), diag::err_main_surplus_args) << nparams; FD->setInvalidDecl(true); nparams = 3; } // FIXME: a lot of the following diagnostics would be improved // if we had some location information about types. QualType CharPP = Context.getPointerType(Context.getPointerType(Context.CharTy)); QualType Expected[] = { Context.IntTy, CharPP, CharPP, CharPP }; for (unsigned i = 0; i < nparams; ++i) { QualType AT = FTP->getParamType(i); bool mismatch = true; if (Context.hasSameUnqualifiedType(AT, Expected[i])) mismatch = false; else if (Expected[i] == CharPP) { // As an extension, the following forms are okay: // char const ** // char const * const * // char * const * QualifierCollector qs; const PointerType* PT; if ((PT = qs.strip(AT)->getAs()) && (PT = qs.strip(PT->getPointeeType())->getAs()) && Context.hasSameType(QualType(qs.strip(PT->getPointeeType()), 0), Context.CharTy)) { qs.removeConst(); mismatch = !qs.empty(); } } if (mismatch) { Diag(FD->getLocation(), diag::err_main_arg_wrong) << i << Expected[i]; // TODO: suggest replacing given type with expected type FD->setInvalidDecl(true); } } if (nparams == 1 && !FD->isInvalidDecl()) { Diag(FD->getLocation(), diag::warn_main_one_arg); } if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); } } void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { QualType T = FD->getType(); assert(T->isFunctionType() && "function decl is not of function type"); const FunctionType *FT = T->castAs(); // Set an implicit return of 'zero' if the function can return some integral, // enumeration, pointer or nullptr type. if (FT->getReturnType()->isIntegralOrEnumerationType() || FT->getReturnType()->isAnyPointerType() || FT->getReturnType()->isNullPtrType()) // DllMain is exempt because a return value of zero means it failed. if (FD->getName() != "DllMain") FD->setHasImplicitReturnZero(true); if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); } } bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { // FIXME: Need strict checking. In C89, we need to check for // any assignment, increment, decrement, function-calls, or // commas outside of a sizeof. In C99, it's the same list, // except that the aforementioned are allowed in unevaluated // expressions. Everything else falls under the // "may accept other forms of constant expressions" exception. // (We never end up here for C++, so the constant expression // rules there don't matter.) const Expr *Culprit; if (Init->isConstantInitializer(Context, false, &Culprit)) return false; Diag(Culprit->getExprLoc(), diag::err_init_element_not_constant) << Culprit->getSourceRange(); return true; } namespace { // Visits an initialization expression to see if OrigDecl is evaluated in // its own initialization and throws a warning if it does. class SelfReferenceChecker : public EvaluatedExprVisitor { Sema &S; Decl *OrigDecl; bool isRecordType; bool isPODType; bool isReferenceType; bool isInitList; llvm::SmallVector InitFieldIndex; public: typedef EvaluatedExprVisitor Inherited; SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), S(S), OrigDecl(OrigDecl) { isPODType = false; isRecordType = false; isReferenceType = false; isInitList = false; if (ValueDecl *VD = dyn_cast(OrigDecl)) { isPODType = VD->getType().isPODType(S.Context); isRecordType = VD->getType()->isRecordType(); isReferenceType = VD->getType()->isReferenceType(); } } // For most expressions, just call the visitor. For initializer lists, // track the index of the field being initialized since fields are // initialized in order allowing use of previously initialized fields. void CheckExpr(Expr *E) { InitListExpr *InitList = dyn_cast(E); if (!InitList) { Visit(E); return; } // Track and increment the index here. isInitList = true; InitFieldIndex.push_back(0); for (auto Child : InitList->children()) { CheckExpr(cast(Child)); ++InitFieldIndex.back(); } InitFieldIndex.pop_back(); } // Returns true if MemberExpr is checked and no futher checking is needed. // Returns false if additional checking is required. bool CheckInitListMemberExpr(MemberExpr *E, bool CheckReference) { llvm::SmallVector Fields; Expr *Base = E; bool ReferenceField = false; // Get the field memebers used. while (MemberExpr *ME = dyn_cast(Base)) { FieldDecl *FD = dyn_cast(ME->getMemberDecl()); if (!FD) return false; Fields.push_back(FD); if (FD->getType()->isReferenceType()) ReferenceField = true; Base = ME->getBase()->IgnoreParenImpCasts(); } // Keep checking only if the base Decl is the same. DeclRefExpr *DRE = dyn_cast(Base); if (!DRE || DRE->getDecl() != OrigDecl) return false; // A reference field can be bound to an unininitialized field. if (CheckReference && !ReferenceField) return true; // Convert FieldDecls to their index number. llvm::SmallVector UsedFieldIndex; for (auto I = Fields.rbegin(), E = Fields.rend(); I != E; ++I) { UsedFieldIndex.push_back((*I)->getFieldIndex()); } // See if a warning is needed by checking the first difference in index // numbers. If field being used has index less than the field being // initialized, then the use is safe. for (auto UsedIter = UsedFieldIndex.begin(), UsedEnd = UsedFieldIndex.end(), OrigIter = InitFieldIndex.begin(), OrigEnd = InitFieldIndex.end(); UsedIter != UsedEnd && OrigIter != OrigEnd; ++UsedIter, ++OrigIter) { if (*UsedIter < *OrigIter) return true; if (*UsedIter > *OrigIter) break; } // TODO: Add a different warning which will print the field names. HandleDeclRefExpr(DRE); return true; } // For most expressions, the cast is directly above the DeclRefExpr. // For conditional operators, the cast can be outside the conditional // operator if both expressions are DeclRefExpr's. void HandleValue(Expr *E) { E = E->IgnoreParens(); if (DeclRefExpr* DRE = dyn_cast(E)) { HandleDeclRefExpr(DRE); return; } if (ConditionalOperator *CO = dyn_cast(E)) { Visit(CO->getCond()); HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); return; } if (BinaryConditionalOperator *BCO = dyn_cast(E)) { Visit(BCO->getCond()); HandleValue(BCO->getFalseExpr()); return; } if (OpaqueValueExpr *OVE = dyn_cast(E)) { HandleValue(OVE->getSourceExpr()); return; } if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { Visit(BO->getLHS()); HandleValue(BO->getRHS()); return; } } if (isa(E)) { if (isInitList) { if (CheckInitListMemberExpr(cast(E), false /*CheckReference*/)) return; } Expr *Base = E->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast(Base)) { // Check for static member variables and don't warn on them. if (!isa(ME->getMemberDecl())) return; Base = ME->getBase()->IgnoreParenImpCasts(); } if (DeclRefExpr *DRE = dyn_cast(Base)) HandleDeclRefExpr(DRE); return; } Visit(E); } // Reference types not handled in HandleValue are handled here since all // uses of references are bad, not just r-value uses. void VisitDeclRefExpr(DeclRefExpr *E) { if (isReferenceType) HandleDeclRefExpr(E); } void VisitImplicitCastExpr(ImplicitCastExpr *E) { if (E->getCastKind() == CK_LValueToRValue) { HandleValue(E->getSubExpr()); return; } Inherited::VisitImplicitCastExpr(E); } void VisitMemberExpr(MemberExpr *E) { if (isInitList) { if (CheckInitListMemberExpr(E, true /*CheckReference*/)) return; } // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; // Warn when a non-static method call is followed by non-static member // field accesses, which is followed by a DeclRefExpr. CXXMethodDecl *MD = dyn_cast(E->getMemberDecl()); bool Warn = (MD && !MD->isStatic()); Expr *Base = E->getBase()->IgnoreParenImpCasts(); while (MemberExpr *ME = dyn_cast(Base)) { if (!isa(ME->getMemberDecl())) Warn = false; Base = ME->getBase()->IgnoreParenImpCasts(); } if (DeclRefExpr *DRE = dyn_cast(Base)) { if (Warn) HandleDeclRefExpr(DRE); return; } // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr. // Visit that expression. Visit(Base); } void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { Expr *Callee = E->getCallee(); if (isa(Callee)) return Inherited::VisitCXXOperatorCallExpr(E); Visit(Callee); for (auto Arg: E->arguments()) HandleValue(Arg->IgnoreParenImpCasts()); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. if (E->getOpcode() == UO_AddrOf && isRecordType && isa(E->getSubExpr()->IgnoreParens())) { if (!isPODType) HandleValue(E->getSubExpr()); return; } if (E->isIncrementDecrementOp()) { HandleValue(E->getSubExpr()); return; } Inherited::VisitUnaryOperator(E); } void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } void VisitCXXConstructExpr(CXXConstructExpr *E) { if (E->getConstructor()->isCopyConstructor()) { Expr *ArgExpr = E->getArg(0); if (InitListExpr *ILE = dyn_cast(ArgExpr)) if (ILE->getNumInits() == 1) ArgExpr = ILE->getInit(0); if (ImplicitCastExpr *ICE = dyn_cast(ArgExpr)) if (ICE->getCastKind() == CK_NoOp) ArgExpr = ICE->getSubExpr(); HandleValue(ArgExpr); return; } Inherited::VisitCXXConstructExpr(E); } void VisitCallExpr(CallExpr *E) { // Treat std::move as a use. if (E->getNumArgs() == 1) { if (FunctionDecl *FD = E->getDirectCallee()) { if (FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { HandleValue(E->getArg(0)); return; } } } Inherited::VisitCallExpr(E); } void VisitBinaryOperator(BinaryOperator *E) { if (E->isCompoundAssignmentOp()) { HandleValue(E->getLHS()); Visit(E->getRHS()); return; } Inherited::VisitBinaryOperator(E); } // A custom visitor for BinaryConditionalOperator is needed because the // regular visitor would check the condition and true expression separately // but both point to the same place giving duplicate diagnostics. void VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { Visit(E->getCond()); Visit(E->getFalseExpr()); } void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; unsigned diag; if (isReferenceType) { diag = diag::warn_uninit_self_reference_in_reference_init; } else if (cast(OrigDecl)->isStaticLocal()) { diag = diag::warn_static_self_reference_in_init; } else { diag = diag::warn_uninit_self_reference_in_init; } S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, S.PDiag(diag) << DRE->getNameInfo().getName() << OrigDecl->getLocation() << DRE->getSourceRange()); } }; /// CheckSelfReference - Warns if OrigDecl is used in expression E. static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E, bool DirectInit) { // Parameters arguments are occassionially constructed with itself, // for instance, in recursive functions. Skip them. if (isa(OrigDecl)) return; E = E->IgnoreParens(); // Skip checking T a = a where T is not a record or reference type. // Doing so is a way to silence uninitialized warnings. if (!DirectInit && !cast(OrigDecl)->getType()->isRecordType()) if (ImplicitCastExpr *ICE = dyn_cast(E)) if (ICE->getCastKind() == CK_LValueToRValue) if (DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr())) if (DRE->getDecl() == OrigDecl) return; SelfReferenceChecker(S, OrigDecl).CheckExpr(E); } } /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (!RealDecl || RealDecl->isInvalidDecl()) { CorrectDelayedTyposInExpr(Init); return; } if (CXXMethodDecl *Method = dyn_cast(RealDecl)) { // With declarators parsed the way they are, the parser cannot // distinguish between a normal initializer and a pure-specifier. // Thus this grotesque test. IntegerLiteral *IL; if ((IL = dyn_cast(Init)) && IL->getValue() == 0 && Context.getCanonicalType(IL->getType()) == Context.IntTy) CheckPureMethod(Method, Init->getSourceRange()); else { Diag(Method->getLocation(), diag::err_member_function_initialization) << Method->getDeclName() << Init->getSourceRange(); Method->setInvalidDecl(); } return; } VarDecl *VDecl = dyn_cast(RealDecl); if (!VDecl) { assert(!isa(RealDecl) && "field init shouldn't get here"); Diag(RealDecl->getLocation(), diag::err_illegal_initializer); RealDecl->setInvalidDecl(); return; } ParenListExpr *CXXDirectInit = dyn_cast(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. if (CXXDirectInit) { if (CXXDirectInit->getNumExprs() == 0) { // It isn't possible to write this directly, but it is possible to // end up in this situation with "auto x(some_pack...);" Diag(CXXDirectInit->getLocStart(), VDecl->isInitCapture() ? diag::err_init_capture_no_expression : diag::err_auto_var_init_no_expression) << VDecl->getDeclName() << VDecl->getType() << VDecl->getSourceRange(); RealDecl->setInvalidDecl(); return; } else if (CXXDirectInit->getNumExprs() > 1) { Diag(CXXDirectInit->getExpr(1)->getLocStart(), VDecl->isInitCapture() ? diag::err_init_capture_multiple_expressions : diag::err_auto_var_init_multiple_expressions) << VDecl->getDeclName() << VDecl->getType() << VDecl->getSourceRange(); RealDecl->setInvalidDecl(); return; } else { DeduceInit = CXXDirectInit->getExpr(0); if (isa(DeduceInit)) Diag(CXXDirectInit->getLocStart(), diag::err_auto_var_init_paren_braces) << VDecl->getDeclName() << VDecl->getType() << VDecl->getSourceRange(); } } // Expressions default to 'id' when we're in a debugger. bool DefaultedToAuto = false; if (getLangOpts().DebuggerCastResultToId && Init->getType() == Context.UnknownAnyTy) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.get(); DefaultedToAuto = true; } QualType DeducedType; if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == DAR_Failed) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); if (DeducedType.isNull()) { RealDecl->setInvalidDecl(); return; } VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); // In ARC, infer lifetime. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); // Warn if we deduced 'id'. 'auto' usually implies type-safety, but using // 'id' instead of a specific object type prevents most of our usual checks. // We only want to warn outside of template instantiations, though: // inside a template, the 'id' could have come from a parameter. if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto && DeducedType->isObjCIdType()) { SourceLocation Loc = VDecl->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); Diag(Loc, diag::warn_auto_var_is_id) << VDecl->getDeclName() << DeduceInit->getSourceRange(); } // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) { // We never need to merge the type, because we cannot form an incomplete // array of auto, nor deduce such a type. MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/false); } // Check the deduced type is valid for a variable declaration. CheckVariableDeclarationType(VDecl); if (VDecl->isInvalidDecl()) return; + + // If all looks well, warn if this is a case that will change meaning when + // we implement N3922. + if (DirectInit && !CXXDirectInit && isa(Init)) { + Diag(Init->getLocStart(), + diag::warn_auto_var_direct_list_init) + << FixItHint::CreateInsertion(Init->getLocStart(), "="); + } } // dllimport cannot be used on variable definitions. if (VDecl->hasAttr() && !VDecl->isStaticDataMember()) { Diag(VDecl->getLocation(), diag::err_attribute_dllimport_data_definition); VDecl->setInvalidDecl(); return; } if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { // C99 6.7.8p5. C++ has no such restriction, but that is a defect. Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); return; } if (!VDecl->getType()->isDependentType()) { // A definition must end up with a complete type, which means it must be // complete with the restriction that an array type might be completed by // the initializer; note that later code assumes this restriction. QualType BaseDeclType = VDecl->getType(); if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) BaseDeclType = Array->getElementType(); if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; } // The variable can not have an abstract class type. if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), diag::err_abstract_type_in_decl, AbstractVariableType)) VDecl->setInvalidDecl(); } const VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl) { Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); VDecl->setInvalidDecl(); return; } const VarDecl *PrevInit = nullptr; if (getLangOpts().CPlusPlus) { // C++ [class.static.data]p4 // If a static data member is of const integral or const // enumeration type, its declaration in the class definition can // specify a constant-initializer which shall be an integral // constant expression (5.19). In that case, the member can appear // in integral constant expressions. The member shall still be // defined in a namespace scope if it is used in the program and the // namespace scope definition shall not contain an initializer. // // We already performed a redefinition check above, but for static // data members we also need to check whether there was an in-class // declaration with an initializer. if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { Diag(Init->getExprLoc(), diag::err_static_data_member_reinitialization) << VDecl->getDeclName(); Diag(PrevInit->getInit()->getExprLoc(), diag::note_previous_initializer) << 0; return; } if (VDecl->hasLocalStorage()) getCurFunction()->setHasBranchProtectedScope(); if (DiagnoseUnexpandedParameterPack(Init, UPPC_Initializer)) { VDecl->setInvalidDecl(); return; } } // OpenCL 1.1 6.5.2: "Variables allocated in the __local address space inside // a kernel function cannot be initialized." if (VDecl->getStorageClass() == SC_OpenCLWorkGroupLocal) { Diag(VDecl->getLocation(), diag::err_local_cant_init); VDecl->setInvalidDecl(); return; } // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; // Expressions default to 'id' when we're in a debugger // and we are assigning it to a variable of Objective-C pointer type. if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() && Init->getType() == Context.UnknownAnyTy) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.get(); } // Perform the initialization. if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = DirectInit ? CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(), Init->getLocStart(), Init->getLocEnd()) : InitializationKind::CreateDirectList( VDecl->getLocation()) : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); MultiExprArg Args = Init; if (CXXDirectInit) Args = MultiExprArg(CXXDirectInit->getExprs(), CXXDirectInit->getNumExprs()); // Try to correct any TypoExprs in the initialization arguments. for (size_t Idx = 0; Idx < Args.size(); ++Idx) { ExprResult Res = CorrectDelayedTyposInExpr(Args[Idx], [this, Entity, Kind](Expr *E) { InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); return Init.Failed() ? ExprError() : E; }); if (Res.isInvalid()) { VDecl->setInvalidDecl(); } else if (Res.get() != Args[Idx]) { Args[Idx] = Res.get(); } } if (VDecl->isInvalidDecl()) return; InitializationSequence InitSeq(*this, Entity, Kind, Args); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.getAs(); } // Check for self-references within variable initializers. // Variables declared within a function/method body (except for references) // are handled by a dataflow analysis. if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || VDecl->getType()->isReferenceType()) { CheckSelfReference(*this, RealDecl, Init, DirectInit); } // If the type changed, it means we had an incomplete type that was // completed by the initializer. For example: // int ary[] = { 1, 3, 5 }; // "ary" transitions from an IncompleteArrayType to a ConstantArrayType. if (!VDecl->isInvalidDecl() && (DclT != SavT)) VDecl->setType(DclT); if (!VDecl->isInvalidDecl()) { checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); if (VDecl->hasAttr()) checkRetainCycles(VDecl, Init); // It is safe to assign a weak reference into a strong variable. // Although this code can still have problems: // id x = self.weakProp; // id y = self.weakProp; // we do not warn to warn spuriously when 'x' and 'y' are on separate // paths through the function. This should be revisited if // -Wrepeated-use-of-weak is made flow-sensitive. if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Init->getLocStart())) getCurFunction()->markSafeWeakUse(Init); } // The initialization is usually a full-expression. // // FIXME: If this is a braced initialization of an aggregate, it is not // an expression, and each individual field initializer is a separate // full-expression. For instance, in: // // struct Temp { ~Temp(); }; // struct S { S(Temp); }; // struct T { S a, b; } t = { Temp(), Temp() } // // we should destroy the first Temp before constructing the second. ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation(), false, VDecl->isConstexpr()); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } Init = Result.get(); // Attach the initializer to the decl. VDecl->setInit(Init); if (VDecl->isLocalVarDecl()) { // C99 6.7.8p4: All the expressions in an initializer for an object that has // static storage duration shall be constant expressions or string literals. // C++ does not have this restriction. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) { const Expr *Culprit; if (VDecl->getStorageClass() == SC_Static) CheckForConstantInitializer(Init, DclT); // C89 is stricter than C99 for non-static aggregate types. // C89 6.5.7p3: All the expressions [...] in an initializer list // for an object that has aggregate or union type shall be // constant expressions. else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && isa(Init) && !Init->isConstantInitializer(Context, false, &Culprit)) Diag(Culprit->getExprLoc(), diag::ext_aggregate_init_not_constant) << Culprit->getSourceRange(); } } else if (VDecl->isStaticDataMember() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., // // struct S { // static const int value = 17; // }; // C++ [class.mem]p4: // A member-declarator can contain a constant-initializer only // if it declares a static member (9.4) of const integral or // const enumeration type, see 9.4.2. // // C++11 [class.static.data]p3: // If a non-volatile const static data member is of integral or // enumeration type, its declaration in the class definition can // specify a brace-or-equal-initializer in which every initalizer-clause // that is an assignment-expression is a constant expression. A static // data member of literal type can be declared in the class definition // with the constexpr specifier; if so, its declaration shall specify a // brace-or-equal-initializer in which every initializer-clause that is // an assignment-expression is a constant expression. // Do nothing on dependent types. if (DclT->isDependentType()) { // Allow any 'static constexpr' members, whether or not they are of literal // type. We separately check that every constexpr variable is of literal // type. } else if (VDecl->isConstexpr()) { // Require constness. } else if (!DclT.isConstQualified()) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const) << Init->getSourceRange(); VDecl->setInvalidDecl(); // We allow integer constant expressions in all cases. } else if (DclT->isIntegralOrEnumerationType()) { // Check whether the expression is a constant expression. SourceLocation Loc; if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified()) // In C++11, a non-constexpr const static data member with an // in-class initializer cannot be volatile. Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile); else if (Init->isValueDependent()) ; // Nothing to check. else if (Init->isIntegerConstantExpr(Context, &Loc)) ; // Ok, it's an ICE! else if (Init->isEvaluatable(Context)) { // If we can constant fold the initializer through heroics, accept it, // but report this as a use of an extension for -pedantic. Diag(Loc, diag::ext_in_class_initializer_non_constant) << Init->getSourceRange(); } else { // Otherwise, this is some crazy unknown case. Report the issue at the // location provided by the isIntegerConstantExpr failed check. Diag(Loc, diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } // We allow foldable floating-point constants as an extension. } else if (DclT->isFloatingType()) { // also permits complex, which is ok // In C++98, this is a GNU extension. In C++11, it is not, but we support // it anyway and provide a fixit to add the 'constexpr'. if (getLangOpts().CPlusPlus11) { Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type_cxx11) << DclT << Init->getSourceRange(); Diag(VDecl->getLocStart(), diag::note_in_class_initializer_float_type_cxx11) << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); } else { Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type) << DclT << Init->getSourceRange(); if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) { Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant) << Init->getSourceRange(); VDecl->setInvalidDecl(); } } // Suggest adding 'constexpr' in C++11 for literal types. } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) << DclT << Init->getSourceRange() << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); VDecl->setConstexpr(true); } else { Diag(VDecl->getLocation(), diag::err_in_class_initializer_bad_type) << DclT << Init->getSourceRange(); VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { if (VDecl->getStorageClass() == SC_Extern && (!getLangOpts().CPlusPlus || !(Context.getBaseElementType(VDecl->getType()).isConstQualified() || VDecl->isExternC())) && !isTemplateInstantiation(VDecl->getTemplateSpecializationKind())) Diag(VDecl->getLocation(), diag::warn_extern_init); // C99 6.7.8p4. All file scoped initializers need to be constant. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) CheckForConstantInitializer(Init, DclT); } // We will represent direct-initialization similarly to copy-initialization: // int x(1); -as-> int x = 1; // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); // // Clients that want to distinguish between the two forms, can check for // direct initializer using VarDecl::getInitStyle(). // A major benefit is that clients that don't particularly care about which // exactly form was it (like the CodeGen) can handle both cases without // special case code. // C++ 8.5p11: // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a // class type. if (CXXDirectInit) { assert(DirectInit && "Call-style initializer must be direct init."); VDecl->setInitStyle(VarDecl::CallInit); } else if (DirectInit) { // This must be list-initialization. No other way is direct-initialization. VDecl->setInitStyle(VarDecl::ListInit); } CheckCompleteVariableDeclaration(VDecl); } /// ActOnInitializerError - Given that there was an error parsing an /// initializer for the given declaration, try to return to some form /// of sanity. void Sema::ActOnInitializerError(Decl *D) { // Our main concern here is re-establishing invariants like "a // variable's type is either dependent or complete". if (!D || D->isInvalidDecl()) return; VarDecl *VD = dyn_cast(D); if (!VD) return; // Auto types are meaningless if we can't make sense of the initializer. if (ParsingInitForAutoVars.count(D)) { D->setInvalidDecl(); return; } QualType Ty = VD->getType(); if (Ty->isDependentType()) return; // Require a complete type. if (RequireCompleteType(VD->getLocation(), Context.getBaseElementType(Ty), diag::err_typecheck_decl_incomplete_type)) { VD->setInvalidDecl(); return; } // Require a non-abstract type. if (RequireNonAbstractType(VD->getLocation(), Ty, diag::err_abstract_type_in_decl, AbstractVariableType)) { VD->setInvalidDecl(); return; } // Don't bother complaining about constructors or destructors, // though. } void Sema::ActOnUninitializedDecl(Decl *RealDecl, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. if (!RealDecl) return; if (VarDecl *Var = dyn_cast(RealDecl)) { QualType Type = Var->getType(); // C++11 [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) << Var->getDeclName() << Type; Var->setInvalidDecl(); return; } // C++11 [class.static.data]p3: A static data member can be declared with // the constexpr specifier; if so, its declaration shall specify // a brace-or-equal-initializer. // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to // the definition of a variable [...] or the declaration of a static data // member. if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) { if (Var->isStaticDataMember()) Diag(Var->getLocation(), diag::err_constexpr_static_mem_var_requires_init) << Var->getDeclName(); else Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); Var->setInvalidDecl(); return; } // OpenCL v1.1 s6.5.3: variables declared in the constant address space must // be initialized. if (!Var->isInvalidDecl() && Var->getType().getAddressSpace() == LangAS::opencl_constant && Var->getStorageClass() != SC_Extern && !Var->getInit()) { Diag(Var->getLocation(), diag::err_opencl_constant_no_init); Var->setInvalidDecl(); return; } switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) break; // We have an out-of-line definition of a static data member // that has an in-class initializer, so we type-check this like // a declaration. // // Fall through case VarDecl::DeclarationOnly: // It's only a declaration. // Block scope. C99 6.7p7: If an identifier for an object is // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->hasLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) Var->setInvalidDecl(); // Make sure that the type is not abstract. if (!Type->isDependentType() && !Var->isInvalidDecl() && RequireNonAbstractType(Var->getLocation(), Type, diag::err_abstract_type_in_decl, AbstractVariableType)) Var->setInvalidDecl(); if (!Type->isDependentType() && !Var->isInvalidDecl() && Var->getStorageClass() == SC_PrivateExtern) { Diag(Var->getLocation(), diag::warn_private_extern); Diag(Var->getLocation(), diag::note_private_extern); } return; case VarDecl::TentativeDefinition: // File scope. C99 6.9.2p2: A declaration of an identifier for an // object that has file scope without an initializer, and without a // storage-class specifier or with the storage-class specifier "static", // constitutes a tentative definition. Note: A tentative definition with // external linkage is valid (C99 6.2.2p5). if (!Var->isInvalidDecl()) { if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(Type)) { if (RequireCompleteType(Var->getLocation(), ArrayT->getElementType(), diag::err_illegal_decl_array_incomplete_type)) Var->setInvalidDecl(); } else if (Var->getStorageClass() == SC_Static) { // C99 6.9.2p3: If the declaration of an identifier for an object is // a tentative definition and has internal linkage (C99 6.2.2p3), the // declared type shall not be an incomplete type. // NOTE: code such as the following // static struct s; // struct s { int a; }; // is accepted by gcc. Hence here we issue a warning instead of // an error and we do not invalidate the static declaration. // NOTE: to avoid multiple warnings, only check the first declaration. if (Var->isFirstDecl()) RequireCompleteType(Var->getLocation(), Type, diag::ext_typecheck_decl_incomplete_type); } } // Record the tentative definition; we're done. if (!Var->isInvalidDecl()) TentativeDefinitions.push_back(Var); return; } // Provide a specific diagnostic for uninitialized variable // definitions with incomplete array type. if (Type->isIncompleteArrayType()) { Diag(Var->getLocation(), diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } // Provide a specific diagnostic for uninitialized variable // definitions with reference type. if (Type->isReferenceType()) { Diag(Var->getLocation(), diag::err_reference_var_requires_init) << Var->getDeclName() << SourceRange(Var->getLocation(), Var->getLocation()); Var->setInvalidDecl(); return; } // Do not attempt to type-check the default initializer for a // variable with dependent type. if (Type->isDependentType()) return; if (Var->isInvalidDecl()) return; if (!Var->hasAttr()) { if (RequireCompleteType(Var->getLocation(), Context.getBaseElementType(Type), diag::err_typecheck_decl_incomplete_type)) { Var->setInvalidDecl(); return; } } // The variable can not have an abstract class type. if (RequireNonAbstractType(Var->getLocation(), Type, diag::err_abstract_type_in_decl, AbstractVariableType)) { Var->setInvalidDecl(); return; } // Check for jumps past the implicit initializer. C++0x // clarifies that this applies to a "variable with automatic // storage duration", not a "local variable". // C++11 [stmt.dcl]p3 // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope is // ill-formed unless the variable has scalar type, class type with a // trivial default constructor and a trivial destructor, a cv-qualified // version of one of these types, or an array of one of the preceding // types and is declared without an initializer. if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) { if (const RecordType *Record = Context.getBaseElementType(Type)->getAs()) { CXXRecordDecl *CXXRecord = cast(Record->getDecl()); // Mark the function for further checking even if the looser rules of // C++11 do not require such checks, so that we can diagnose // incompatibilities with C++98. if (!CXXRecord->isPOD()) getCurFunction()->setHasBranchProtectedScope(); } } // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or // array thereof), the object shall be default-initialized; if // the object is of const-qualified type, the underlying class // type shall have a user-declared default // constructor. Otherwise, if no initializer is specified for // a non- static object, the object and its subobjects, if // any, have an indeterminate initial value); if the object // or any of its subobjects are of const-qualified type, the // program is ill-formed. // C++0x [dcl.init]p11: // If no initializer is specified for an object, the object is // default-initialized; [...]. InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); InitializationSequence InitSeq(*this, Entity, Kind, None); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); // This is important for template substitution. Var->setInitStyle(VarDecl::CallInit); } CheckCompleteVariableDeclaration(Var); } } void Sema::ActOnCXXForRangeDecl(Decl *D) { VarDecl *VD = dyn_cast(D); if (!VD) { Diag(D->getLocation(), diag::err_for_range_decl_must_be_var); D->setInvalidDecl(); return; } VD->setCXXForRangeDecl(true); // for-range-declaration cannot be given a storage class specifier. int Error = -1; switch (VD->getStorageClass()) { case SC_None: break; case SC_Extern: Error = 0; break; case SC_Static: Error = 1; break; case SC_PrivateExtern: Error = 2; break; case SC_Auto: Error = 3; break; case SC_Register: Error = 4; break; case SC_OpenCLWorkGroupLocal: llvm_unreachable("Unexpected storage class"); } if (VD->isConstexpr()) Error = 5; if (Error != -1) { Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) << VD->getDeclName() << Error; D->setInvalidDecl(); } } StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd) { // C++1y [stmt.iter]p1: // A range-based for statement of the form // for ( for-range-identifier : for-range-initializer ) statement // is equivalent to // for ( auto&& for-range-identifier : for-range-initializer ) statement DeclSpec DS(Attrs.getPool().getFactory()); const char *PrevSpec; unsigned DiagID; DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID, getPrintingPolicy()); Declarator D(DS, Declarator::ForContext); D.SetIdentifier(Ident, IdentLoc); D.takeAttributes(Attrs, AttrEnd); ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory()); D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/false), EmptyAttrs, IdentLoc); Decl *Var = ActOnDeclarator(S, D); cast(Var)->setCXXForRangeDecl(true); FinalizeDeclaration(Var); return ActOnDeclStmt(FinalizeDeclaratorGroup(S, DS, Var), IdentLoc, AttrEnd.isValid() ? AttrEnd : IdentLoc); } void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; // In ARC, don't allow jumps past the implicit initialization of a // local retaining variable. if (getLangOpts().ObjCAutoRefCount && var->hasLocalStorage()) { switch (var->getType().getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: getCurFunction()->setHasBranchProtectedScope(); break; } } // Warn about externally-visible variables being defined without a // prior declaration. We only want to do this for global // declarations, but we also specifically need to avoid doing it for // class members because the linkage of an anonymous class can // change if it's later given a typedef name. if (var->isThisDeclarationADefinition() && var->getDeclContext()->getRedeclContext()->isFileContext() && var->isExternallyVisible() && var->hasLinkage() && !getDiagnostics().isIgnored(diag::warn_missing_variable_declarations, var->getLocation())) { // Find a previous declaration that's not a definition. VarDecl *prev = var->getPreviousDecl(); while (prev && prev->isThisDeclarationADefinition()) prev = prev->getPreviousDecl(); if (!prev) Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } if (var->getTLSKind() == VarDecl::TLS_Static) { const Expr *Culprit; if (var->getType().isDestructedType()) { // GNU C++98 edits for __thread, [basic.start.term]p3: // The type of an object with thread storage duration shall not // have a non-trivial destructor. Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); } else if (getLangOpts().CPlusPlus && var->hasInit() && !var->getInit()->isConstantInitializer( Context, var->getType()->isReferenceType(), &Culprit)) { // GNU C++98 edits for __thread, [basic.start.init]p4: // An object of thread storage duration shall not require dynamic // initialization. // FIXME: Need strict checking here. Diag(Culprit->getExprLoc(), diag::err_thread_dynamic_init) << Culprit->getSourceRange(); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); } } if (var->isThisDeclarationADefinition() && ActiveTemplateInstantiations.empty()) { PragmaStack *Stack = nullptr; int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read; if (var->getType().isConstQualified()) Stack = &ConstSegStack; else if (!var->getInit()) { Stack = &BSSSegStack; SectionFlags |= ASTContext::PSF_Write; } else { Stack = &DataSegStack; SectionFlags |= ASTContext::PSF_Write; } if (!var->hasAttr() && Stack->CurrentValue) var->addAttr( SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation)); if (const SectionAttr *SA = var->getAttr()) if (UnifySection(SA->getName(), SectionFlags, var)) var->dropAttr(); // Apply the init_seg attribute if this has an initializer. If the // initializer turns out to not be dynamic, we'll end up ignoring this // attribute. if (CurInitSeg && var->getInit()) var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(), CurInitSegLoc)); } // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; QualType type = var->getType(); if (type->isDependentType()) return; // __block variables might require us to capture a copy-initializer. if (var->hasAttr()) { // It's currently invalid to ever have a __block variable with an // array type; should we diagnose that here? // Regardless, we don't want to ignore array nesting when // constructing this copy. if (type->isStructureOrClassType()) { EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated); SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); ExprResult result = PerformMoveOrCopyInitialization( InitializedEntity::InitializeBlock(poi, type, false), var, var->getType(), varRef, /*AllowNRVO=*/true); if (!result.isInvalid()) { result = MaybeCreateExprWithCleanups(result); Expr *init = result.getAs(); Context.setBlockVarCopyInits(var, init); } } } Expr *Init = var->getInit(); bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); if (!var->getDeclContext()->isDependentContext() && Init && !Init->isValueDependent()) { if (IsGlobal && !var->isConstexpr() && !getDiagnostics().isIgnored(diag::warn_global_constructor, var->getLocation())) { // Warn about globals which don't have a constant initializer. Don't // warn about globals with a non-trivial destructor because we already // warned about them. CXXRecordDecl *RD = baseType->getAsCXXRecordDecl(); if (!(RD && !RD->hasTrivialDestructor()) && !Init->isConstantInitializer(Context, baseType->isReferenceType())) Diag(var->getLocation(), diag::warn_global_constructor) << Init->getSourceRange(); } if (var->isConstexpr()) { SmallVector Notes; if (!var->evaluateValue(Notes) || !var->isInitICE()) { SourceLocation DiagLoc = var->getLocation(); // If the note doesn't add any useful information other than a source // location, fold it into the primary diagnostic. if (Notes.size() == 1 && Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) { DiagLoc = Notes[0].first; Notes.clear(); } Diag(DiagLoc, diag::err_constexpr_var_requires_const_init) << var << Init->getSourceRange(); for (unsigned I = 0, N = Notes.size(); I != N; ++I) Diag(Notes[I].first, Notes[I].second); } } else if (var->isUsableInConstantExpressions(Context)) { // Check whether the initializer of a const variable of integral or // enumeration type is an ICE now, since we can't tell whether it was // initialized by a constant expression if we check later. var->checkInitIsICE(); } } // Require the destructor. if (const RecordType *recordType = baseType->getAs()) FinalizeVarWithDestructor(var, recordType); } /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. void Sema::FinalizeDeclaration(Decl *ThisDecl) { // Note that we are no longer parsing the initializer for this declaration. ParsingInitForAutoVars.erase(ThisDecl); VarDecl *VD = dyn_cast_or_null(ThisDecl); if (!VD) return; checkAttributesAfterMerging(*this, *VD); // Static locals inherit dll attributes from their function. if (VD->isStaticLocal()) { if (FunctionDecl *FD = dyn_cast_or_null(VD->getParentFunctionOrMethod())) { if (Attr *A = getDLLAttr(FD)) { auto *NewAttr = cast(A->clone(getASTContext())); NewAttr->setInherited(true); VD->addAttr(NewAttr); } } } // Grab the dllimport or dllexport attribute off of the VarDecl. const InheritableAttr *DLLAttr = getDLLAttr(VD); // Imported static data members cannot be defined out-of-line. if (const auto *IA = dyn_cast_or_null(DLLAttr)) { if (VD->isStaticDataMember() && VD->isOutOfLine() && VD->isThisDeclarationADefinition()) { // We allow definitions of dllimport class template static data members // with a warning. CXXRecordDecl *Context = cast(VD->getFirstDecl()->getDeclContext()); bool IsClassTemplateMember = isa(Context) || Context->getDescribedClassTemplate(); Diag(VD->getLocation(), IsClassTemplateMember ? diag::warn_attribute_dllimport_static_field_definition : diag::err_attribute_dllimport_static_field_definition); Diag(IA->getLocation(), diag::note_attribute); if (!IsClassTemplateMember) VD->setInvalidDecl(); } } // dllimport/dllexport variables cannot be thread local, their TLS index // isn't exported with the variable. if (DLLAttr && VD->getTLSKind()) { Diag(VD->getLocation(), diag::err_attribute_dll_thread_local) << VD << DLLAttr; VD->setInvalidDecl(); } if (UsedAttr *Attr = VD->getAttr()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; VD->dropAttr(); } } if (!VD->isInvalidDecl() && VD->isThisDeclarationADefinition() == VarDecl::TentativeDefinition) { if (const VarDecl *Def = VD->getDefinition()) { if (Def->hasAttr()) { Diag(VD->getLocation(), diag::err_tentative_after_alias) << VD->getDeclName(); Diag(Def->getLocation(), diag::note_previous_definition); VD->setInvalidDecl(); } } } const DeclContext *DC = VD->getDeclContext(); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. if (DC->getRedeclContext()->isFileContext() && VD->isExternallyVisible()) AddPushedVisibilityAttribute(VD); // FIXME: Warn on unused templates. if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() && !isa(VD)) MarkUnusedFileScopedDecl(VD); // Now we have parsed the initializer and can update the table of magic // tag values. if (!VD->hasAttr() || !VD->getType()->isIntegralOrEnumerationType()) return; for (const auto *I : ThisDecl->specific_attrs()) { const Expr *MagicValueExpr = VD->getInit(); if (!MagicValueExpr) { continue; } llvm::APSInt MagicValueInt; if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) { Diag(I->getRange().getBegin(), diag::err_type_tag_for_datatype_not_ice) << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); continue; } if (MagicValueInt.getActiveBits() > 64) { Diag(I->getRange().getBegin(), diag::err_type_tag_for_datatype_too_large) << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange(); continue; } uint64_t MagicValue = MagicValueInt.getZExtValue(); RegisterTypeTagForDatatype(I->getArgumentKind(), MagicValue, I->getMatchingCType(), I->getLayoutCompatible(), I->getMustBeNull()); } } Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group) { SmallVector Decls; if (DS.isTypeSpecOwned()) Decls.push_back(DS.getRepAsDecl()); DeclaratorDecl *FirstDeclaratorInGroup = nullptr; for (unsigned i = 0, e = Group.size(); i != e; ++i) if (Decl *D = Group[i]) { if (DeclaratorDecl *DD = dyn_cast(D)) if (!FirstDeclaratorInGroup) FirstDeclaratorInGroup = DD; Decls.push_back(D); } if (DeclSpec::isDeclRep(DS.getTypeSpecType())) { if (TagDecl *Tag = dyn_cast_or_null(DS.getRepAsDecl())) { HandleTagNumbering(*this, Tag, S); if (!Tag->hasNameForLinkage() && !Tag->hasDeclaratorForAnonDecl()) Tag->setDeclaratorForAnonDecl(FirstDeclaratorInGroup); } } return BuildDeclaratorGroup(Decls, DS.containsPlaceholderType()); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration /// group, performing any necessary semantic checking. Sema::DeclGroupPtrTy Sema::BuildDeclaratorGroup(MutableArrayRef Group, bool TypeMayContainAuto) { // C++0x [dcl.spec.auto]p7: // If the type deduced for the template parameter U is not the same in each // deduction, the program is ill-formed. // FIXME: When initializer-list support is added, a distinction is needed // between the deduced type U and the deduced type which 'auto' stands for. // auto a = 0, b = { 1, 2, 3 }; // is legal because the deduced type U is 'int' in both cases. if (TypeMayContainAuto && Group.size() > 1) { QualType Deduced; CanQualType DeducedCanon; VarDecl *DeducedDecl = nullptr; for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (VarDecl *D = dyn_cast(Group[i])) { AutoType *AT = D->getType()->getContainedAutoType(); // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; QualType U = AT ? AT->getDeducedType() : QualType(); if (!U.isNull()) { CanQualType UCanon = Context.getCanonicalType(U); if (Deduced.isNull()) { Deduced = U; DeducedCanon = UCanon; DeducedDecl = D; } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) << (AT->isDecltypeAuto() ? 1 : 0) << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() << D->getInit()->getSourceRange(); D->setInvalidDecl(); break; } } } } } ActOnDocumentableDecls(Group); return DeclGroupPtrTy::make( DeclGroupRef::Create(Context, Group.data(), Group.size())); } void Sema::ActOnDocumentableDecl(Decl *D) { ActOnDocumentableDecls(D); } void Sema::ActOnDocumentableDecls(ArrayRef Group) { // Don't parse the comment if Doxygen diagnostics are ignored. if (Group.empty() || !Group[0]) return; if (Diags.isIgnored(diag::warn_doc_param_not_found, Group[0]->getLocation())) return; if (Group.size() >= 2) { // This is a decl group. Normally it will contain only declarations // produced from declarator list. But in case we have any definitions or // additional declaration references: // 'typedef struct S {} S;' // 'typedef struct S *S;' // 'struct S *pS;' // FinalizeDeclaratorGroup adds these as separate declarations. Decl *MaybeTagDecl = Group[0]; if (MaybeTagDecl && isa(MaybeTagDecl)) { Group = Group.slice(1); } } // See if there are any new comments that are not attached to a decl. ArrayRef Comments = Context.getRawCommentList().getComments(); if (!Comments.empty() && !Comments.back()->isAttached()) { // There is at least one comment that not attached to a decl. // Maybe it should be attached to one of these decls? // // Note that this way we pick up not only comments that precede the // declaration, but also comments that *follow* the declaration -- thanks to // the lookahead in the lexer: we've consumed the semicolon and looked // ahead through comments. for (unsigned i = 0, e = Group.size(); i != e; ++i) Context.getCommentForDecl(Group[i], &PP); } } /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. // C++03 [dcl.stc]p2 also permits 'auto'. StorageClass SC = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { SC = SC_Register; } else if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_auto) { SC = SC_Auto; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); D.getMutableDeclSpec().ClearStorageClassSpecs(); } if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); if (DS.isConstexprSpecified()) Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; DiagnoseFunctionSpecifiers(DS); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType parmDeclType = TInfo->getType(); if (getLangOpts().CPlusPlus) { // Check that there are no default arguments inside the type of this // parameter. CheckExtraCXXDefaultArguments(D); // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) << D.getCXXScopeSpec().getRange(); D.getCXXScopeSpec().clear(); } } // Ensure we have a valid name IdentifierInfo *II = nullptr; if (D.hasName()) { II = D.getIdentifier(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_parameter_name) << GetNameForDeclarator(D).getName(); D.setInvalidType(true); } } // Check for redeclaration of parameters, e.g. int foo(int x, int x); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); LookupName(R, S); if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } else if (S->isDeclScope(PrevDecl)) { Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); // Recover by removing the name II = nullptr; D.SetIdentifier(nullptr, D.getIdentifierLoc()); D.setInvalidType(true); } } } // Temporarily put parameter variables in the translation unit, not // the enclosing context. This prevents them from accidentally // looking like class members in C++. ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), D.getLocStart(), D.getIdentifierLoc(), II, parmDeclType, TInfo, SC); if (D.isInvalidType()) New->setInvalidDecl(); assert(S->isFunctionPrototypeScope()); assert(S->getFunctionPrototypeDepth() >= 1); New->setScopeInfo(S->getFunctionPrototypeDepth() - 1, S->getNextFunctionPrototypeIndex()); // Add the parameter declaration into this scope. S->AddDecl(New); if (II) IdResolver.AddDecl(New); ProcessDeclAttributes(S, New, D); if (D.getDeclSpec().isModulePrivateSpecified()) Diag(New->getLocation(), diag::err_module_private_local) << 1 << New->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); if (New->hasAttr()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } return New; } /// \brief Synthesizes a variable for a parameter arising from a /// typedef. ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T) { /* FIXME: setting StartLoc == Loc. Would it be worth to modify callers so as to provide proper source location for the unnamed parameters, embedding the parameter's type? */ ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, nullptr, T, Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr); Param->setImplicit(); return Param; } void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd) { // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (!ActiveTemplateInstantiations.empty()) return; for (; Param != ParamEnd; ++Param) { if (!(*Param)->isReferenced() && (*Param)->getDeclName() && !(*Param)->hasAttr()) { Diag((*Param)->getLocation(), diag::warn_unused_parameter) << (*Param)->getDeclName(); } } } void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, ParmVarDecl * const *ParamEnd, QualType ReturnTy, NamedDecl *D) { if (LangOpts.NumLargeByValueCopy == 0) // No check. return; // Warn if the return value is pass-by-value and larger than the specified // threshold. if (!ReturnTy->isDependentType() && ReturnTy.isPODType(Context)) { unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag(D->getLocation(), diag::warn_return_value_size) << D->getDeclName() << Size; } // Warn if any parameter is pass-by-value and larger than the specified // threshold. for (; Param != ParamEnd; ++Param) { QualType T = (*Param)->getType(); if (T->isDependentType() || !T.isPODType(Context)) continue; unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) Diag((*Param)->getLocation(), diag::warn_parameter_size) << (*Param)->getDeclName() << Size; } } ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && T->isObjCLifetimeType()) { Qualifiers::ObjCLifetime lifetime; // Special cases for arrays: // - if it's const, use __unsafe_unretained // - otherwise, it's an error if (T->isArrayType()) { if (!T.isConstQualified()) { DelayedDiagnostics.add( sema::DelayedDiagnostic::makeForbiddenType( NameLoc, diag::err_arc_array_param_no_ownership, T, false)); } lifetime = Qualifiers::OCL_ExplicitNone; } else { lifetime = T->getObjCARCImplicitLifetime(); } T = Context.getLifetimeQualifiedType(T, lifetime); } ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. if (!CurContext->isRecord() && RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl, AbstractParamType)) New->setInvalidDecl(); // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { SourceLocation TypeEndLoc = TSInfo->getTypeLoc().getLocEnd(); Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T << FixItHint::CreateInsertion(TypeEndLoc, "*"); T = Context.getObjCObjectPointerType(T); New->setType(T); } // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. if (T.getAddressSpace() != 0) { // OpenCL allows function arguments declared to be an array of a type // to be qualified with an address space. if (!(getLangOpts().OpenCL && T->isArrayType())) { Diag(NameLoc, diag::err_arg_with_address_space); New->setInvalidDecl(); } } return New; } void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls) { DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. if (!FTI.hasPrototype) { for (int i = FTI.NumParams; i != 0; /* decrement in loop */) { --i; if (FTI.Params[i].Param == nullptr) { SmallString<256> Code; llvm::raw_svector_ostream(Code) << " int " << FTI.Params[i].Ident->getName() << ";\n"; Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared) << FTI.Params[i].Ident << FixItHint::CreateInsertion(LocAfterDecls, Code.str()); // Implicitly declare the argument as type 'int' for lack of a better // type. AttributeFactory attrs; DeclSpec DS(attrs); const char* PrevSpec; // unused unsigned DiagID; // unused DS.SetTypeSpecType(DeclSpec::TST_int, FTI.Params[i].IdentLoc, PrevSpec, DiagID, Context.getPrintingPolicy()); // Use the identifier location for the type source range. DS.SetRangeStart(FTI.Params[i].IdentLoc); DS.SetRangeEnd(FTI.Params[i].IdentLoc); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc); FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD); } } } } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(getCurFunctionDecl() == nullptr && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); return ActOnStartOfFunctionDef(FnBodyScope, DP); } void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) { Consumer.HandleInlineMethodDefinition(D); } static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, const FunctionDecl*& PossibleZeroParamPrototype) { // Don't warn about invalid declarations. if (FD->isInvalidDecl()) return false; // Or declarations that aren't global. if (!FD->isGlobal()) return false; // Don't warn about C++ member functions. if (isa(FD)) return false; // Don't warn about 'main'. if (FD->isMain()) return false; // Don't warn about inline functions. if (FD->isInlined()) return false; // Don't warn about function templates. if (FD->getDescribedFunctionTemplate()) return false; // Don't warn about function template specializations. if (FD->isFunctionTemplateSpecialization()) return false; // Don't warn for OpenCL kernels. if (FD->hasAttr()) return false; bool MissingPrototype = true; for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { // Ignore any declarations that occur in function or method // scope, because they aren't visible from the header. if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) continue; MissingPrototype = !Prev->getType()->isFunctionProtoType(); if (FD->getNumParams() == 0) PossibleZeroParamPrototype = Prev; break; } return MissingPrototype; } void Sema::CheckForFunctionRedefinition(FunctionDecl *FD, const FunctionDecl *EffectiveDefinition) { // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition = EffectiveDefinition; if (!Definition) if (!FD->isDefined(Definition)) return; if (canRedefineFunction(Definition, getLangOpts())) return; if (getLangOpts().GNUMode && Definition->isInlineSpecified() && Definition->getStorageClass() == SC_Extern) Diag(FD->getLocation(), diag::err_redefinition_extern_inline) << FD->getDeclName() << getLangOpts().CPlusPlus; else Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); FD->setInvalidDecl(); } static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, Sema &S) { CXXRecordDecl *const LambdaClass = CallOperator->getParent(); LambdaScopeInfo *LSI = S.PushLambdaScope(); LSI->CallOperator = CallOperator; LSI->Lambda = LambdaClass; LSI->ReturnType = CallOperator->getReturnType(); const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault(); if (LCD == LCD_None) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_None; else if (LCD == LCD_ByCopy) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByval; else if (LCD == LCD_ByRef) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref; DeclarationNameInfo DNI = CallOperator->getNameInfo(); LSI->IntroducerRange = DNI.getCXXOperatorNameRange(); LSI->Mutable = !CallOperator->isConst(); // Add the captures to the LSI so they can be noted as already // captured within tryCaptureVar. auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), CaptureType, /*Expr*/ nullptr); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), S.getCurrentThisType(), /*Expr*/ nullptr); } else { LSI->addVLATypeCapture(C.getLocation(), I->getType()); } ++I; } } Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); if (!D) return D; FunctionDecl *FD = nullptr; if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) FD = FunTmpl->getTemplatedDecl(); else FD = cast(D); // If we are instantiating a generic lambda call operator, push // a LambdaScopeInfo onto the function stack. But use the information // that's already been calculated (ActOnLambdaExpr) to prime the current // LambdaScopeInfo. // When the template operator is being specialized, the LambdaScopeInfo, // has to be properly restored so that tryCaptureVariable doesn't try // and capture any new variables. In addition when calculating potential // captures during transformation of nested lambdas, it is necessary to // have the LSI properly restored. if (isGenericLambdaCallOperatorSpecialization(FD)) { assert(ActiveTemplateInstantiations.size() && "There should be an active template instantiation on the stack " "when instantiating a generic lambda!"); RebuildLambdaScopeInfo(cast(D), *this); } else // Enter a new function scope PushFunctionScope(); // See if this is a redefinition. if (!FD->isLateTemplateParsed()) CheckForFunctionRedefinition(FD); // Builtin functions cannot be defined. if (unsigned BuiltinID = FD->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) && !Context.BuiltinInfo.isPredefinedRuntimeFunction(BuiltinID)) { Diag(FD->getLocation(), diag::err_builtin_definition) << FD; FD->setInvalidDecl(); } } // The return type of a function definition must be complete // (C99 6.9.1p3, C++ [dcl.fct]p6). QualType ResultType = FD->getReturnType(); if (!ResultType->isDependentType() && !ResultType->isVoidType() && !FD->isInvalidDecl() && RequireCompleteType(FD->getLocation(), ResultType, diag::err_func_def_incomplete_result)) FD->setInvalidDecl(); // GNU warning -Wmissing-prototypes: // Warn if a global function is defined without a previous // prototype declaration. This warning is issued even if the // definition itself provides a prototype. The aim is to detect // global functions that fail to be declared in header files. const FunctionDecl *PossibleZeroParamPrototype = nullptr; if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) { Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; if (PossibleZeroParamPrototype) { // We found a declaration that is not a prototype, // but that could be a zero-parameter prototype if (TypeSourceInfo *TI = PossibleZeroParamPrototype->getTypeSourceInfo()) { TypeLoc TL = TI->getTypeLoc(); if (FunctionNoProtoTypeLoc FTL = TL.getAs()) Diag(PossibleZeroParamPrototype->getLocation(), diag::note_declaration_not_a_prototype) << PossibleZeroParamPrototype << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void"); } } } if (FnBodyScope) PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(), /*CheckParameterNames=*/true); // Introduce our parameters into the function scope for (auto Param : FD->params()) { Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. if (Param->getIdentifier() && FnBodyScope) { CheckShadow(FnBodyScope, Param); PushOnScopeChains(Param, FnBodyScope); } } // If we had any tags defined in the function prototype, // introduce them into the function scope. if (FnBodyScope) { for (ArrayRef::iterator I = FD->getDeclsInPrototypeScope().begin(), E = FD->getDeclsInPrototypeScope().end(); I != E; ++I) { NamedDecl *D = *I; // Some of these decls (like enums) may have been pinned to the translation unit // for lack of a real context earlier. If so, remove from the translation unit // and reattach to the current context. if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) { // Is the decl actually in the context? for (const auto *DI : Context.getTranslationUnitDecl()->decls()) { if (DI == D) { Context.getTranslationUnitDecl()->removeDecl(D); break; } } // Either way, reassign the lexical decl context to our FunctionDecl. D->setLexicalDeclContext(CurContext); } // If the decl has a non-null name, make accessible in the current scope. if (!D->getName().empty()) PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false); // Similarly, dive into enums and fish their constants out, making them // accessible in this scope. if (auto *ED = dyn_cast(D)) { for (auto *EI : ED->enumerators()) PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); } } } // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs()) ResolveExceptionSpec(D->getLocation(), FPT); // dllimport cannot be applied to non-inline function definitions. if (FD->hasAttr() && !FD->isInlined() && !FD->isTemplateInstantiation()) { assert(!FD->hasAttr()); Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition); FD->setInvalidDecl(); return D; } // We want to attach documentation to original Decl (which might be // a function template). ActOnDocumentableDecl(D); if (getCurLexicalContext()->isObjCContainer() && getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl && getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation) Diag(FD->getLocation(), diag::warn_function_def_in_objc_container); return D; } /// \brief Given the set of return statements within a function body, /// compute the variables that are subject to the named return value /// optimization. /// /// Each of the variables that is subject to the named return value /// optimization will be marked as NRVO variables in the AST, and any /// return statement that has a marked NRVO variable as its NRVO candidate can /// use the named return value optimization. /// /// This function applies a very simplistic algorithm for NRVO: if every return /// statement in the scope of a variable has the same NRVO candidate, that /// candidate is an NRVO variable. void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { ReturnStmt **Returns = Scope->Returns.data(); for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) { if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) { if (!NRVOCandidate->isNRVOVariable()) Returns[I]->setNRVOCandidate(nullptr); } } } bool Sema::canDelayFunctionBody(const Declarator &D) { // We can't delay parsing the body of a constexpr function template (yet). if (D.getDeclSpec().isConstexprSpecified()) return false; // We can't delay parsing the body of a function template with a deduced // return type (yet). if (D.getDeclSpec().containsPlaceholderType()) { // If the placeholder introduces a non-deduced trailing return type, // we can still delay parsing it. if (D.getNumTypeObjects()) { const auto &Outer = D.getTypeObject(D.getNumTypeObjects() - 1); if (Outer.Kind == DeclaratorChunk::Function && Outer.Fun.hasTrailingReturnType()) { QualType Ty = GetTypeFromParser(Outer.Fun.getTrailingReturnType()); return Ty.isNull() || !Ty->isUndeducedType(); } } return false; } return true; } bool Sema::canSkipFunctionBody(Decl *D) { // We cannot skip the body of a function (or function template) which is // constexpr, since we may need to evaluate its body in order to parse the // rest of the file. // We cannot skip the body of a function with an undeduced return type, // because any callers of that function need to know the type. if (const FunctionDecl *FD = D->getAsFunction()) if (FD->isConstexpr() || FD->getReturnType()->isUndeducedType()) return false; return Consumer.shouldSkipFunctionBody(D); } Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) { if (FunctionDecl *FD = dyn_cast_or_null(Decl)) FD->setHasSkippedBody(); else if (ObjCMethodDecl *MD = dyn_cast_or_null(Decl)) MD->setHasSkippedBody(); return ActOnFinishFunctionBody(Decl, nullptr); } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { return ActOnFinishFunctionBody(D, BodyArg, false); } Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation) { FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr; sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; if (FD) { FD->setBody(Body); if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body && !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { // If the function has a deduced result type but contains no 'return' // statements, the result type as written must be exactly 'auto', and // the deduced result type is 'void'. if (!FD->getReturnType()->getAs()) { Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) << FD->getReturnType(); FD->setInvalidDecl(); } else { // Substitute 'void' for the 'auto' in the type. TypeLoc ResultType = getReturnTypeLoc(FD); Context.adjustDeducedFunctionResultType( FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); } } // The only way to be included in UndefinedButUsed is if there is an // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) { if (!FD->isExternallyVisible()) UndefinedButUsed.erase(FD); else if (FD->isInlined() && (LangOpts.CPlusPlus || !LangOpts.GNUInline) && (!FD->getPreviousDecl()->hasAttr())) UndefinedButUsed.erase(FD); } // If the function implicitly returns zero (like 'main') or is naked, // don't complain about missing return statements. if (FD->hasImplicitReturnZero() || FD->hasAttr()) WP.disableCheckFallThrough(); // MSVC permits the use of pure specifier (=0) on function definition, // defined at class scope, warn about this non-standard construct. if (getLangOpts().MicrosoftExt && FD->isPure() && FD->isCanonicalDecl()) Diag(FD->getLocation(), diag::ext_pure_function_definition); if (!FD->isInvalidDecl()) { // Don't diagnose unused parameters of defaulted or deleted functions. if (Body) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), FD->getReturnType(), FD); // If this is a structor, we need a vtable. if (CXXConstructorDecl *Constructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); else if (CXXDestructorDecl *Destructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Destructor->getParent()); // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around // to deduce an implicit return type. if (getLangOpts().CPlusPlus && FD->getReturnType()->isRecordType() && !FD->isDependentContext()) computeNRVO(Body, getCurFunction()); } assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); if (!MD->isInvalidDecl()) { DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), MD->getReturnType(), MD); if (Body) computeNRVO(Body, getCurFunction()); } if (getCurFunction()->ObjCShouldCallSuper) { Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call) << MD->getSelector().getAsString(); getCurFunction()->ObjCShouldCallSuper = false; } if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) { const ObjCMethodDecl *InitMethod = nullptr; bool isDesignated = MD->isDesignatedInitializerForTheInterface(&InitMethod); assert(isDesignated && InitMethod); (void)isDesignated; auto superIsNSObject = [&](const ObjCMethodDecl *MD) { auto IFace = MD->getClassInterface(); if (!IFace) return false; auto SuperD = IFace->getSuperClass(); if (!SuperD) return false; return SuperD->getIdentifier() == NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); }; // Don't issue this warning for unavailable inits or direct subclasses // of NSObject. if (!MD->isUnavailable() && !superIsNSObject(MD)) { Diag(MD->getLocation(), diag::warn_objc_designated_init_missing_super_call); Diag(InitMethod->getLocation(), diag::note_objc_designated_init_marked_here); } getCurFunction()->ObjCWarnForNoDesignatedInitChain = false; } if (getCurFunction()->ObjCWarnForNoInitDelegation) { // Don't issue this warning for unavaialable inits. if (!MD->isUnavailable()) Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call); getCurFunction()->ObjCWarnForNoInitDelegation = false; } } else { return nullptr; } assert(!getCurFunction()->ObjCShouldCallSuper && "This should only be set for ObjC methods, which should have been " "handled in the block above."); // Verify and clean out per-function state. if (Body) { // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) // Verify this. if (FD && isa(FD) && isa(Body)) DiagnoseReturnInConstructorExceptionHandler(cast(Body)); // Verify that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { if (!Destructor->getParent()->isDependentType()) CheckDestructor(Destructor); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); } // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (getDiagnostics().hasErrorOccurred() || getDiagnostics().getSuppressAllDiagnostics()) { DiscardCleanupsInEvaluationContext(); } if (!getDiagnostics().hasUncompilableErrorOccurred() && !isa(dcl)) { // Since the body is valid, issue any analysis-based warnings that are // enabled. ActivePolicy = &WP; } if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && (!CheckConstexprFunctionDecl(FD) || !CheckConstexprFunctionBody(FD, Body))) FD->setInvalidDecl(); if (FD && FD->hasAttr()) { for (const Stmt *S : Body->children()) { if (!isa(S) && !isa(S)) { Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function); Diag(FD->getAttr()->getLocation(), diag::note_attribute); FD->setInvalidDecl(); break; } } } assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects && "Leftover temporaries in function"); assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); assert(MaybeODRUseExprs.empty() && "Leftover expressions for odr-use checking"); } if (!IsInstantiation) PopDeclContext(); PopFunctionScopeInfo(ActivePolicy, dcl); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (getDiagnostics().hasErrorOccurred()) { DiscardCleanupsInEvaluationContext(); } return dcl; } /// When we finish delayed parsing of an attribute, we must attach it to the /// relevant Decl. void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs) { // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast(D)) D = TD->getTemplatedDecl(); ProcessDeclAttributeList(S, D, Attrs.getList()); if (CXXMethodDecl *Method = dyn_cast_or_null(D)) if (Method->isStatic()) checkThisInStaticMemberFunctionAttributes(Method); } /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S) { // Before we produce a declaration for an implicitly defined // function, see whether there was a locally-scoped declaration of // this name as a function or variable. If so, use that // (non-visible) declaration, and complain about it. if (NamedDecl *ExternCPrev = findLocallyScopedExternCDecl(&II)) { Diag(Loc, diag::warn_use_out_of_scope_declaration) << ExternCPrev; Diag(ExternCPrev->getLocation(), diag::note_previous_declaration); return ExternCPrev; } // Extension in C99. Legal in C90, but warn about it. unsigned diag_id; if (II.getName().startswith("__builtin_")) diag_id = diag::warn_builtin_unknown; else if (getLangOpts().C99) diag_id = diag::ext_implicit_function_decl; else diag_id = diag::warn_implicit_function_decl; Diag(Loc, diag_id) << &II; // Because typo correction is expensive, only do it if the implicit // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { TypoCorrection Corrected; if (S && (Corrected = CorrectTypo( DeclarationNameInfo(&II, Loc), LookupOrdinaryName, S, nullptr, llvm::make_unique>(), CTK_NonError))) diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion), /*ErrorRecovery*/false); } // Set a Declarator for the implicit definition: int foo(); const char *Dummy; AttributeFactory attrFactory; DeclSpec DS(attrFactory); unsigned DiagID; bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID, Context.getPrintingPolicy()); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); SourceLocation NoLoc; Declarator D(DS, Declarator::BlockContext); D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false, /*IsAmbiguous=*/false, /*LParenLoc=*/NoLoc, /*Params=*/nullptr, /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, /*TypeQuals=*/0, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, /*ConstQualifierLoc=*/NoLoc, /*VolatileQualifierLoc=*/NoLoc, /*RestrictQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecLoc=*/NoLoc, /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); // Insert this function into translation-unit scope. DeclContext *PrevDC = CurContext; CurContext = Context.getTranslationUnitDecl(); FunctionDecl *FD = cast(ActOnDeclarator(TUScope, D)); FD->setImplicit(); CurContext = PrevDC; AddKnownFunctionAttributes(FD); return FD; } /// \brief Adds any function attributes that we know a priori based on /// the declaration of this function. /// /// These attributes can apply both to implicitly-declared builtins /// (like __builtin___printf_chk) or to library-declared functions /// like NSLog or printf. /// /// We need to check for duplicate attributes both here and where user-written /// attributes are applied to declarations. void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (FD->isInvalidDecl()) return; // If this is a built-in function, map its builtin attributes to // actual attributes. if (unsigned BuiltinID = FD->getBuiltinID()) { // Handle printf-formatting attributes. unsigned FormatIdx; bool HasVAListArg; if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->hasAttr()) { const char *fmt = "printf"; unsigned int NumParams = FD->getNumParams(); if (FormatIdx < NumParams && // NumParams may be 0 (e.g. vfprintf) FD->getParamDecl(FormatIdx)->getType()->isObjCObjectPointerType()) fmt = "NSString"; FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get(fmt), FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2, FD->getLocation())); } } if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->hasAttr()) FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get("scanf"), FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2, FD->getLocation())); } // Mark const if we don't care about errno and that is the only // thing preventing the function from being const. This allows // IRgen to use LLVM intrinsics for such functions. if (!getLangOpts().MathErrno && Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { if (!FD->hasAttr()) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); } if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->hasAttr()) FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr()) FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr()) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); } IdentifierInfo *Name = FD->getIdentifier(); if (!Name) return; if ((!getLangOpts().CPlusPlus && FD->getDeclContext()->isTranslationUnit()) || (isa(FD->getDeclContext()) && cast(FD->getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c)) { // Okay: this could be a libc/libm/Objective-C function we know // about. } else return; if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { // FIXME: asprintf and vasprintf aren't C99 functions. Should they be // target-specific builtins, perhaps? if (!FD->hasAttr()) FD->addAttr(FormatAttr::CreateImplicit(Context, &Context.Idents.get("printf"), 2, Name->isStr("vasprintf") ? 0 : 3, FD->getLocation())); } if (Name->isStr("__CFStringMakeConstantString")) { // We already have a __builtin___CFStringMakeConstantString, // but builds that use -fno-constant-cfstrings don't go through that. if (!FD->hasAttr()) FD->addAttr(FormatArgAttr::CreateImplicit(Context, 1, FD->getLocation())); } } TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); if (!TInfo) { assert(D.isInvalidType() && "no declarator info for valid type"); TInfo = Context.getTrivialTypeSourceInfo(T); } // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getLocStart(), D.getIdentifierLoc(), D.getIdentifier(), TInfo); // Bail out immediately if we have an invalid declaration. if (D.isInvalidType()) { NewTD->setInvalidDecl(); return NewTD; } if (D.getDeclSpec().isModulePrivateSpecified()) { if (CurContext->isFunctionOrMethod()) Diag(NewTD->getLocation(), diag::err_module_private_local) << 2 << NewTD->getDeclName() << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); else NewTD->setModulePrivate(); } // C++ [dcl.typedef]p8: // If the typedef declaration defines an unnamed class (or // enum), the first typedef-name declared by the declaration // to be that class type (or enum type) is used to denote the // class type (or enum type) for linkage purposes only. // We need to check whether the type was declared in the declaration. switch (D.getDeclSpec().getTypeSpecType()) { case TST_enum: case TST_struct: case TST_interface: case TST_union: case TST_class: { TagDecl *tagFromDeclSpec = cast(D.getDeclSpec().getRepAsDecl()); // Do nothing if the tag is not anonymous or already has an // associated typedef (from an earlier typedef in this decl group). if (tagFromDeclSpec->getIdentifier()) break; if (tagFromDeclSpec->getTypedefNameForAnonDecl()) break; // A well-formed anonymous tag must always be a TUK_Definition. assert(tagFromDeclSpec->isThisDeclarationADefinition()); // The type must match the tag exactly; no qualifiers allowed. if (!Context.hasSameType(T, Context.getTagDeclType(tagFromDeclSpec))) break; // If we've already computed linkage for the anonymous tag, then // adding a typedef name for the anonymous decl can change that // linkage, which might be a serious problem. Diagnose this as // unsupported and ignore the typedef name. TODO: we should // pursue this as a language defect and establish a formal rule // for how to handle it. if (tagFromDeclSpec->hasLinkageBeenComputed()) { Diag(D.getIdentifierLoc(), diag::err_typedef_changes_linkage); SourceLocation tagLoc = D.getDeclSpec().getTypeSpecTypeLoc(); tagLoc = getLocForEndOfToken(tagLoc); llvm::SmallString<40> textToInsert; textToInsert += ' '; textToInsert += D.getIdentifier()->getName(); Diag(tagLoc, diag::note_typedef_changes_linkage) << FixItHint::CreateInsertion(tagLoc, textToInsert); break; } // Otherwise, set this is the anon-decl typedef for the tag. tagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); break; } default: break; } return NewTD; } /// \brief Check that this is a valid underlying type for an enum declaration. bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); QualType T = TI->getType(); if (T->isDependentType()) return false; if (const BuiltinType *BT = T->getAs()) if (BT->isInteger()) return false; Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T; return true; } /// Check whether this is a valid redeclaration of a previous enumeration. /// \return true if the redeclaration was invalid. bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, const EnumDecl *Prev) { bool IsFixed = !EnumUnderlyingTy.isNull(); if (IsScoped != Prev->isScoped()) { Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch) << Prev->isScoped(); Diag(Prev->getLocation(), diag::note_previous_declaration); return true; } if (IsFixed && Prev->isFixed()) { if (!EnumUnderlyingTy->isDependentType() && !Prev->getIntegerType()->isDependentType() && !Context.hasSameUnqualifiedType(EnumUnderlyingTy, Prev->getIntegerType())) { // TODO: Highlight the underlying type of the redeclaration. Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch) << EnumUnderlyingTy << Prev->getIntegerType(); Diag(Prev->getLocation(), diag::note_previous_declaration) << Prev->getIntegerTypeRange(); return true; } } else if (IsFixed != Prev->isFixed()) { Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch) << Prev->isFixed(); Diag(Prev->getLocation(), diag::note_previous_declaration); return true; } return false; } /// \brief Get diagnostic %select index for tag kind for /// redeclaration diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// /// \returns diagnostic %select index. static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) { switch (Tag) { case TTK_Struct: return 0; case TTK_Interface: return 1; case TTK_Class: return 2; default: llvm_unreachable("Invalid tag kind for redecl diagnostic!"); } } /// \brief Determine if tag kind is a class-key compatible with /// class for redeclaration (class, struct, or __interface). /// /// \returns true iff the tag kind is compatible. static bool isClassCompatTagKind(TagTypeKind Tag) { return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; } /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// /// \returns true if the new tag kind is acceptable, false otherwise. bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo &Name) { // C++ [dcl.type.elab]p3: // The class-key or enum keyword present in the // elaborated-type-specifier shall agree in kind with the // declaration to which the name in the elaborated-type-specifier // refers. This rule also applies to the form of // elaborated-type-specifier that declares a class-name or // friend class since it can be construed as referring to the // definition of the class. Thus, in any // elaborated-type-specifier, the enum keyword shall be used to // refer to an enumeration (7.2), the union class-key shall be // used to refer to a union (clause 9), and either the class or // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); if (!isDefinition || !isClassCompatTagKind(NewTag)) if (OldTag == NewTag) return true; if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast(Previous)) isTemplate = Record->getDescribedClassTemplate(); if (!ActiveTemplateInstantiations.empty()) { // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name << getRedeclDiagFromTagKind(OldTag); return true; } if (isDefinition) { // On definitions, check previous tags and issue a fix-it for each // one that doesn't match the current tag. if (Previous->getDefinition()) { // Don't suggest fix-its for redefinitions. return true; } bool previousMismatch = false; for (auto I : Previous->redecls()) { if (I->getTagKind() != NewTag) { if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) << getRedeclDiagFromTagKind(NewTag) << FixItHint::CreateReplacement(I->getInnerLocStart(), TypeWithKeyword::getTagTypeKindName(NewTag)); } } return true; } // Check for a previous definition. If current tag and definition // are same type, do nothing. If no definition, but disagree with // with previous tag type, give a warning, but no fix-it. const TagDecl *Redecl = Previous->getDefinition() ? Previous->getDefinition() : Previous; if (Redecl->getTagKind() == NewTag) { return true; } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous definition, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) << getRedeclDiagFromTagKind(Redecl->getTagKind()) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind())); } return true; } return false; } /// Add a minimal nested name specifier fixit hint to allow lookup of a tag name /// from an outer enclosing namespace or file scope inside a friend declaration. /// This should provide the commented out code in the following snippet: /// namespace N { /// struct X; /// namespace M { /// struct Y { friend struct /*N::*/ X; }; /// } /// } static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, SourceLocation NameLoc) { // While the decl is in a namespace, do repeated lookup of that name and see // if we get the same namespace back. If we do not, continue until // translation unit scope, at which point we have a fully qualified NNS. SmallVector Namespaces; DeclContext *DC = ND->getDeclContext()->getRedeclContext(); for (; !DC->isTranslationUnit(); DC = DC->getParent()) { // This tag should be declared in a namespace, which can only be enclosed by // other namespaces. Bail if there's an anonymous namespace in the chain. NamespaceDecl *Namespace = dyn_cast(DC); if (!Namespace || Namespace->isAnonymousNamespace()) return FixItHint(); IdentifierInfo *II = Namespace->getIdentifier(); Namespaces.push_back(II); NamedDecl *Lookup = SemaRef.LookupSingleName( S, II, NameLoc, Sema::LookupNestedNameSpecifierName); if (Lookup == Namespace) break; } // Once we have all the namespaces, reverse them to go outermost first, and // build an NNS. SmallString<64> Insertion; llvm::raw_svector_ostream OS(Insertion); if (DC->isTranslationUnit()) OS << "::"; std::reverse(Namespaces.begin(), Namespaces.end()); for (auto *II : Namespaces) OS << II->getName() << "::"; OS.flush(); return FixItHint::CreateInsertion(NameLoc, Insertion); } /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. /// /// IsTypeSpecifier is true if this is a type-specifier (or /// trailing-type-specifier) other than one in an alias-declaration. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && "Nameless record must be a definition!"); assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool ScopedEnum = ScopedEnumKWLoc.isValid(); // FIXME: Check explicit specializations more carefully. bool isExplicitSpecialization = false; bool Invalid = false; // We only need to do this matching if we have template parameters // or a scope specifier, which also conveniently avoids this work // for non-C++ cases. if (TemplateParameterLists.size() > 0 || (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( KWLoc, NameLoc, SS, nullptr, TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { if (Kind == TTK_Enum) { Diag(KWLoc, diag::err_enum_template); return nullptr; } if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). if (Invalid) return nullptr; OwnedDecl = false; DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, /*FriendLoc*/SourceLocation(), TemplateParameterLists.size()-1, TemplateParameterLists.data()); return Result.get(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) << TypeWithKeyword::getTagTypeKindName(Kind) << Name; isExplicitSpecialization = true; } } } // Figure out the underlying type if this a enum declaration. We need to do // this early, because it's needed to detect if this is an incompatible // redeclaration. llvm::PointerUnion EnumUnderlying; if (Kind == TTK_Enum) { if (UnderlyingType.isInvalid() || (!UnderlyingType.get() && ScopedEnum)) // No underlying type explicitly specified, or we failed to parse the // type, default to int. EnumUnderlying = Context.IntTy.getTypePtr(); else if (UnderlyingType.get()) { // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an // integral type; any cv-qualification is ignored. TypeSourceInfo *TI = nullptr; GetTypeFromParser(UnderlyingType.get(), &TI); EnumUnderlying = TI; if (CheckEnumUnderlyingType(TI)) // Recover by falling back to int. EnumUnderlying = Context.IntTy.getTypePtr(); if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI, UPPC_FixedUnderlyingType)) EnumUnderlying = Context.IntTy.getTypePtr(); } else if (getLangOpts().MSVCCompat) // Microsoft enums are always of int type. EnumUnderlying = Context.IntTy.getTypePtr(); } DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; RedeclarationKind Redecl = ForRedeclaration; if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). // Check for invalid 'foo::'. if (SS.isInvalid()) { Name = nullptr; goto CreateNewDecl; } // If this is a friend or a reference to a class in a dependent // context, don't try to make a decl for it. if (TUK == TUK_Friend || TUK == TUK_Reference) { DC = computeDeclContext(SS, false); if (!DC) { IsDependent = true; return nullptr; } } else { DC = computeDeclContext(SS, true); if (!DC) { Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) << SS.getRange(); return nullptr; } } if (RequireCompleteDeclContext(SS, DC)) return nullptr; SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); if (Previous.isAmbiguous()) return nullptr; if (Previous.empty()) { // Name lookup did not find anything. However, if the // nested-name-specifier refers to the current instantiation, // and that current instantiation has any dependent base // classes, we might find something at instantiation time: treat // this as a dependent elaborated-type-specifier. // But this only makes any sense for reference-like lookups. if (Previous.wasNotFoundInCurrentInstantiation() && (TUK == TUK_Reference || TUK == TUK_Friend)) { IsDependent = true; return nullptr; } // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Kind << Name << DC << SS.getRange(); Name = nullptr; Invalid = true; goto CreateNewDecl; } } else if (Name) { // If this is a named struct, check to see if there was a previous forward // declaration or definition. // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. LookupName(Previous, S); // When declaring or defining a tag, ignore ambiguities introduced // by types using'ed into this scope. if (Previous.isAmbiguous() && (TUK == TUK_Definition || TUK == TUK_Declaration)) { LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *ND = F.next(); if (ND->getDeclContext()->getRedeclContext() != SearchDC) F.erase(); } F.done(); } // C++11 [namespace.memdef]p3: // If the name in a friend declaration is neither qualified nor // a template-id and the declaration is a function or an // elaborated-type-specifier, the lookup to determine whether // the entity has been previously declared shall not consider // any scopes outside the innermost enclosing namespace. // // MSVC doesn't implement the above rule for types, so a friend tag // declaration may be a redeclaration of a type declared in an enclosing // scope. They do implement this rule for friend functions. // // Does it matter that this should be by scope instead of by // semantic context? if (!Previous.empty() && TUK == TUK_Friend) { DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext(); LookupResult::Filter F = Previous.makeFilter(); bool FriendSawTagOutsideEnclosingNamespace = false; while (F.hasNext()) { NamedDecl *ND = F.next(); DeclContext *DC = ND->getDeclContext()->getRedeclContext(); if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext())) { if (getLangOpts().MSVCCompat) FriendSawTagOutsideEnclosingNamespace = true; else F.erase(); } } F.done(); // Diagnose this MSVC extension in the easy case where lookup would have // unambiguously found something outside the enclosing namespace. if (Previous.isSingleResult() && FriendSawTagOutsideEnclosingNamespace) { NamedDecl *ND = Previous.getFoundDecl(); Diag(NameLoc, diag::ext_friend_tag_redecl_outside_namespace) << createFriendTagNNSFixIt(*this, ND, S, NameLoc); } } // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) return nullptr; if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated // with C structs, unions, and enums when looking for a matching // tag declaration or definition. See the similar lookup tweak // in Sema::LookupName; is there a better way to deal with this? while (isa(SearchDC) || isa(SearchDC)) SearchDC = SearchDC->getParent(); } } if (Previous.isSingleResult() && Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. Previous.clear(); } if (getLangOpts().CPlusPlus && Name && DC && StdNamespace && DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; if (Previous.empty() && StdBadAlloc) { // std::bad_alloc has been implicitly declared (but made invisible to // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. Previous.addDecl(getStdBadAlloc()); } } // If we didn't find a previous declaration, and this is a reference // (or friend reference), move to the correct scope. In C++, we // also need to do a redeclaration lookup there, just in case // there's a shadow friend decl. if (Name && Previous.empty() && (TUK == TUK_Reference || TUK == TUK_Friend)) { if (Invalid) goto CreateNewDecl; assert(SS.isEmpty()); if (TUK == TUK_Reference) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // // class-key identifier // // if the elaborated-type-specifier is used in the // decl-specifier-seq or parameter-declaration-clause of a // function defined in namespace scope, the identifier is // declared as a class-name in the namespace that contains // the declaration; otherwise, except as a friend // declaration, the identifier is declared in the smallest // non-class, non-function-prototype scope that contains the // declaration. // // C99 6.7.2.3p8 has a similar (but not identical!) provision for // C structs and unions. // // It is an error in C++ to declare (rather than define) an enum // type, including via an elaborated type specifier. We'll // diagnose that later; for now, declare the enum in the same // scope as we would have picked for any other tag type. // // GNU C also supports this behavior as part of its incomplete // enum types extension, while GNU C++ does not. // // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the // lexical context, while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod()) SearchDC = SearchDC->getParent(); // Find the scope where we'll be declaring the tag. while (S->isClassScope() || (getLangOpts().CPlusPlus && S->isFunctionPrototypeScope()) || ((S->getFlags() & Scope::DeclScope) == 0) || (S->getEntity() && S->getEntity()->isTransparentContext())) S = S->getParent(); } else { assert(TUK == TUK_Friend); // C++ [namespace.memdef]p3: // If a friend declaration in a non-local class first declares a // class or function, the friend class or function is a member of // the innermost enclosing namespace. SearchDC = SearchDC->getEnclosingNamespaceContext(); } // In C++, we need to do a redeclaration lookup to properly // diagnose some problems. if (getLangOpts().CPlusPlus) { Previous.setRedeclarationKind(ForRedeclaration); LookupQualifiedName(Previous, SearchDC); } } if (!Previous.empty()) { NamedDecl *PrevDecl = Previous.getFoundDecl(); NamedDecl *DirectPrevDecl = getLangOpts().MSVCCompat ? *Previous.begin() : PrevDecl; // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this // insanity with a redeclaration lookup can only actually happen // in C++. // // This is also okay for elaborated-type-specifiers, which is // technically forbidden by the current standard but which is // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 if (getLangOpts().CPlusPlus) { if (TypedefNameDecl *TD = dyn_cast(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); if (Tag->getDeclName() == Name && Tag->getDeclContext()->getRedeclContext() ->Equals(TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag); Previous.resolveKind(); } } } } if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. if (TUK == TUK_Reference || TUK == TUK_Friend || isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, TUK == TUK_Definition, KWLoc, *Name)) { bool SafeToContinue = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum); if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name << FixItHint::CreateReplacement(SourceRange(KWLoc), PrevTagDecl->getKindName()); else Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_use); if (SafeToContinue) Kind = PrevTagDecl->getTagKind(); else { // Recover by making this an anonymous redefinition. Name = nullptr; Previous.clear(); Invalid = true; } } if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { const EnumDecl *PrevEnum = cast(PrevTagDecl); // If this is an elaborated-type-specifier for a scoped enumeration, // the 'class' keyword is not necessary and not permitted. if (TUK == TUK_Reference || TUK == TUK_Friend) { if (ScopedEnum) Diag(ScopedEnumKWLoc, diag::err_enum_class_reference) << PrevEnum->isScoped() << FixItHint::CreateRemoval(ScopedEnumKWLoc); return PrevTagDecl; } QualType EnumUnderlyingTy; if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast()) EnumUnderlyingTy = TI->getType().getUnqualifiedType(); else if (const Type *T = EnumUnderlying.dyn_cast()) EnumUnderlyingTy = QualType(T, 0); // All conflicts with previous declarations are recovered by // returning the previous declaration, unless this is a definition, // in which case we want the caller to bail out. if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc, ScopedEnum, EnumUnderlyingTy, PrevEnum)) return TUK == TUK_Declaration ? PrevTagDecl : nullptr; } // C++11 [class.mem]p1: // A member shall not be declared twice in the member-specification, // except that a nested class or member class template can be declared // and then later defined. if (TUK == TUK_Declaration && PrevDecl->isCXXClassMember() && S->isDeclScope(PrevDecl)) { Diag(NameLoc, diag::ext_member_redeclared); Diag(PrevTagDecl->getLocation(), diag::note_previous_declaration); } if (!Invalid) { // If this is a use, just return the declaration we found, unless // we have attributes. // FIXME: In the future, return a variant or some other clue // for the consumer of this Decl to know it doesn't own it. // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. if (!Attr && ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() || getLangOpts().MicrosoftExt)) || TUK == TUK_Friend)) return PrevTagDecl; // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { if (TagDecl *Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error // here; we'll catch this in the general case below. bool IsExplicitSpecializationAfterInstantiation = false; if (isExplicitSpecialization) { if (CXXRecordDecl *RD = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = RD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; else if (EnumDecl *ED = dyn_cast(Def)) IsExplicitSpecializationAfterInstantiation = ED->getTemplateSpecializationKind() != TSK_ExplicitSpecialization; } if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't // visible elsewhere, so merely issue a warning. if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope()) Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name; else Diag(NameLoc, diag::err_redefinition) << Name; Diag(Def->getLocation(), diag::note_previous_definition); // If this is a redefinition, recover by making this // struct be anonymous, which will make any later // references get the previous definition. Name = nullptr; Previous.clear(); Invalid = true; } } else { // If the type is currently being defined, complain // about a nested redefinition. auto *TD = Context.getTagDeclType(PrevTagDecl)->getAsTagDecl(); if (TD->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = nullptr; Previous.clear(); Invalid = true; } } // Okay, this is definition of a previously declared or referenced // tag. We're going to create a new Decl for it. } // Okay, we're going to make a redeclaration. If this is some kind // of reference, make sure we build the redeclaration in the same DC // as the original, and ignore the current access specifier. if (TUK == TUK_Friend || TUK == TUK_Reference) { SearchDC = PrevTagDecl->getDeclContext(); AS = AS_none; } } // If we get here we have (another) forward declaration or we // have a definition. Just create a new decl. } else { // If we get here, this is a definition of a new tag type in a nested // scope, e.g. "struct foo; void bar() { struct foo; }", just create a // new decl/type. We set PrevDecl to NULL so that the entities // have distinct types. Previous.clear(); } // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. // Otherwise, PrevDecl is not a tag, but was found with tag // lookup. This is only actually possible in C++, where a few // things like templates still live in the tag namespace. } else { // Use a better diagnostic if an elaborated-type-specifier // found the wrong kind of type on the first // (non-redeclaration) lookup. if ((TUK == TUK_Reference || TUK == TUK_Friend) && !Previous.isForRedeclaration()) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; else if (isa(PrevDecl)) Kind = 2; else if (isa(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; // Otherwise, only diagnose if the declaration is in scope. } else if (!isDeclInScope(PrevDecl, SearchDC, S, SS.isNotEmpty() || isExplicitSpecialization)) { // do nothing // Diagnose implicit declarations introduced by elaborated types. } else if (TUK == TUK_Reference || TUK == TUK_Friend) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; else if (isa(PrevDecl)) Kind = 2; else if (isa(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise it's a declaration. Call out a particularly common // case here. } else if (TypedefNameDecl *TND = dyn_cast(PrevDecl)) { unsigned Kind = 0; if (isa(PrevDecl)) Kind = 1; Diag(NameLoc, diag::err_tag_definition_of_typedef) << Name << Kind << TND->getUnderlyingType(); Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise, diagnose. } else { // The tag name clashes with something else in the target scope, // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = nullptr; Invalid = true; } // The existing declaration isn't relevant to us; we're in a // new scope, so clear out the previous declaration. Previous.clear(); } } CreateNewDecl: TagDecl *PrevDecl = nullptr; if (Previous.isSingleResult()) PrevDecl = cast(Previous.getFoundDecl()); // If there is an identifier, use the location of the identifier as the // location of the decl, otherwise use the location of the struct/union // keyword. SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; // Otherwise, create a new declaration. If there is a previous // declaration of the same entity, the two will be linked via // PrevDecl. TagDecl *New; bool IsForwardReference = false; if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl), ScopedEnum, ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) && cast(New)->isFixed()) { // C++0x: 7.2p2: opaque-enum-declaration. // Conflicts are diagnosed above. Do nothing. } else if (PrevDecl && (Def = cast(PrevDecl)->getDefinition())) { Diag(Loc, diag::ext_forward_ref_enum_def) << New; Diag(Def->getLocation(), diag::note_previous_definition); } else { unsigned DiagID = diag::ext_forward_ref_enum; if (getLangOpts().MSVCCompat) DiagID = diag::ext_ms_forward_ref_enum; else if (getLangOpts().CPlusPlus) DiagID = diag::err_forward_ref_enum; Diag(Loc, DiagID); // If this is a forward-declared reference to an enumeration, make a // note of it; we won't actually be introducing the declaration into // the declaration context. if (TUK == TUK_Reference) IsForwardReference = true; } } if (EnumUnderlying) { EnumDecl *ED = cast(New); if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast()) ED->setIntegerTypeSourceInfo(TI); else ED->setIntegerType(QualType(EnumUnderlying.get(), 0)); ED->setPromotionType(ED->getIntegerType()); } } else { // struct/union/class // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // struct X { int A; } D; D should chain to X. if (getLangOpts().CPlusPlus) { // FIXME: Look for a way to use RecordDecl for simple structs. New = CXXRecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl)); if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit())) StdBadAlloc = cast(New); } else New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null(PrevDecl)); } // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration [...]. if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) { Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTagDeclType(New); Invalid = true; } // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { // If this is either a declaration or a definition, check the // nested-name-specifier against the current context. We don't do this // for explicit specializations, because they have similar checking // (with more specific diagnostics) in the call to // CheckMemberSpecialization, below. if (!isExplicitSpecialization && (TUK == TUK_Definition || TUK == TUK_Declaration) && diagnoseQualifiedDeclaration(SS, DC, OrigName, Loc)) Invalid = true; New->setQualifierInfo(SS.getWithLocInContext(Context)); if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), TemplateParameterLists.data()); } } else Invalid = true; } if (RecordDecl *RD = dyn_cast(New)) { // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this // happen here (in act on tag decl). The #pragma pack stack is // maintained as a result of parser callbacks which can occur at // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the // parsing of the struct). if (TUK == TUK_Definition) { AddAlignmentAttributesForRecord(RD); AddMsStructLayoutForRecord(RD); } } if (ModulePrivateLoc.isValid()) { if (isExplicitSpecialization) Diag(New->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(ModulePrivateLoc); // __module_private__ does not apply to local classes. However, we only // diagnose this as an error when the declaration specifiers are // freestanding. Here, we just ignore the __module_private__. else if (!SearchDC->isFunctionOrMethod()) New->setModulePrivate(); } // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; // If we're declaring or defining a tag in function prototype scope in C, // note that this type can only be used within the function and add it to // the list of decls to inject into the function definition scope. if ((Name || Kind == TTK_Enum) && getNonFieldDeclScope(S)->isFunctionPrototypeScope()) { if (getLangOpts().CPlusPlus) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. if (TUK == TUK_Definition && !IsTypeSpecifier) { Diag(Loc, diag::err_type_defined_in_param_type) << Name; Invalid = true; } } else { Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); } DeclsInPrototypeScope.push_back(New); } if (Invalid) New->setInvalidDecl(); if (Attr) ProcessDeclAttributeList(S, New, Attr); // Set the lexical context. If the tag has a C++ scope specifier, the // lexical context will be different from the semantic context. New->setLexicalDeclContext(CurContext); // Mark this as a friend decl if applicable. // In Microsoft mode, a friend declaration also acts as a forward // declaration so we always pass true to setObjectOfFriendDecl to make // the tag name visible. if (TUK == TUK_Friend) New->setObjectOfFriendDecl(getLangOpts().MSVCCompat); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); if (TUK == TUK_Definition) New->startDefinition(); // If this has an identifier, add it to the scope stack. if (TUK == TUK_Friend) { // We might be replacing an existing declaration in the lookup tables; // if so, borrow its access specifier. if (PrevDecl) New->setAccess(PrevDecl->getAccess()); DeclContext *DC = New->getDeclContext()->getRedeclContext(); DC->makeDeclVisibleInContext(New); if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); } else if (Name) { S = getNonFieldDeclScope(S); PushOnScopeChains(New, S, !IsForwardReference); if (IsForwardReference) SearchDC->makeDeclVisibleInContext(New); } else { CurContext->addDecl(New); } // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = New->getIdentifier()) if (!New->isInvalidDecl() && New->getDeclContext()->getRedeclContext()->isTranslationUnit() && II->isStr("FILE")) Context.setFILEDecl(New); if (PrevDecl) mergeDeclAttributes(New, PrevDecl); // If there's a #pragma GCC visibility in scope, set the visibility of this // record. AddPushedVisibilityAttribute(New); OwnedDecl = true; // In C++, don't return an invalid declaration. We can't recover well from // the cases where we make the type anonymous. return (Invalid && getLangOpts().CPlusPlus) ? nullptr : New; } void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); // Enter the tag context. PushDeclContext(S, Tag); ActOnDocumentableDecl(TagD); // If there's a #pragma GCC visibility in scope, set the visibility of this // record. AddPushedVisibilityAttribute(Tag); } Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast(IDecl); assert(getContainingDC(OCD) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = OCD; return IDecl; } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast(TagD); FieldCollector->StartClass(); if (!Record->getIdentifier()) return; if (FinalLoc.isValid()) Record->addAttr(new (Context) FinalAttr(FinalLoc, Context, IsFinalSpelledSealed)); // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For // purposes of access checking, the injected-class-name is treated // as if it were a public member name. CXXRecordDecl *InjectedClassName = CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext, Record->getLocStart(), Record->getLocation(), Record->getIdentifier(), /*PrevDecl=*/nullptr, /*DelayTypeCreation=*/true); Context.getTypeDeclType(InjectedClassName, Record); InjectedClassName->setImplicit(); InjectedClassName->setAccess(AS_public); if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) InjectedClassName->setDescribedClassTemplate(Template); PushOnScopeChains(InjectedClassName, S); assert(InjectedClassName->isInjectedClassName() && "Broken injected-class-name"); } void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); Tag->setRBraceLoc(RBraceLoc); // Make sure we "complete" the definition even it is invalid. if (Tag->isBeingDefined()) { assert(Tag->isInvalidDecl() && "We should already have completed it"); if (RecordDecl *RD = dyn_cast(Tag)) RD->completeDefinition(); } if (isa(Tag)) FieldCollector->FinishClass(); // Exit this scope of this tag's definition. PopDeclContext(); if (getCurLexicalContext()->isObjCContainer() && Tag->getDeclContext()->isFileContext()) Tag->setTopLevelDeclInObjCContainer(); // Notify the consumer that we've defined a tag. if (!Tag->isInvalidDecl()) Consumer.HandleTagDeclDefinition(Tag); } void Sema::ActOnObjCContainerFinishDefinition() { // Exit this scope of this interface definition. PopDeclContext(); } void Sema::ActOnObjCTemporaryExitContainerContext(DeclContext *DC) { assert(DC == CurContext && "Mismatch of container contexts"); OriginalLexicalContext = DC; ActOnObjCContainerFinishDefinition(); } void Sema::ActOnObjCReenterContainerContext(DeclContext *DC) { ActOnObjCContainerStartDefinition(cast(DC)); OriginalLexicalContext = nullptr; } void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast(TagD); Tag->setInvalidDecl(); // Make sure we "complete" the definition even it is invalid. if (Tag->isBeingDefined()) { if (RecordDecl *RD = dyn_cast(Tag)) RD->completeDefinition(); } // We're undoing ActOnTagStartDefinition here, not // ActOnStartCXXMemberDeclarations, so we don't have to mess with // the FieldCollector. PopDeclContext(); } // Note that FieldName may be null for anonymous bitfields. ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth) { // Default to true; that shouldn't confuse checks for emptiness if (ZeroWidth) *ZeroWidth = true; // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) { // Handle incomplete types with specific error. if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete)) return ExprError(); if (FieldName) return Diag(FieldLoc, diag::err_not_integral_type_bitfield) << FieldName << FieldTy << BitWidth->getSourceRange(); return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield) << FieldTy << BitWidth->getSourceRange(); } else if (DiagnoseUnexpandedParameterPack(const_cast(BitWidth), UPPC_BitFieldWidth)) return ExprError(); // If the bit-width is type- or value-dependent, don't try to check // it now. if (BitWidth->isValueDependent() || BitWidth->isTypeDependent()) return BitWidth; llvm::APSInt Value; ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Value); if (ICE.isInvalid()) return ICE; BitWidth = ICE.get(); if (Value != 0 && ZeroWidth) *ZeroWidth = false; // Zero-width bitfield is ok for anonymous field. if (Value == 0 && FieldName) return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; if (Value.isSigned() && Value.isNegative()) { if (FieldName) return Diag(FieldLoc, diag::err_bitfield_has_negative_width) << FieldName << Value.toString(10); return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width) << Value.toString(10); } if (!FieldTy->isDependentType()) { uint64_t TypeSize = Context.getTypeSize(FieldTy); if (Value.getZExtValue() > TypeSize) { if (!getLangOpts().CPlusPlus || IsMsStruct || Context.getTargetInfo().getCXXABI().isMicrosoft()) { if (FieldName) return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) << FieldName << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } if (FieldName) Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size) << FieldName << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; else Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size) << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } } return BitWidth; } /// ActOnField - Each field of a C struct/union is passed into this in order /// to create a FieldDecl object for it. Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth) { FieldDecl *Res = HandleField(S, cast_or_null(TagD), DeclStart, D, static_cast(BitfieldWidth), /*InitStyle=*/ICIS_NoInit, AS_public); return Res; } /// HandleField - Analyze a field of a C struct or a C++ data member. /// FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation DeclStart, Declarator &D, Expr *BitWidth, InClassInitStyle InitStyle, AccessSpecifier AS) { IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (getLangOpts().CPlusPlus) { CheckExtraCXXDefaultArguments(D); if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, UPPC_DataMemberType)) { D.setInvalidType(); T = Context.IntTy; TInfo = Context.getTrivialTypeSourceInfo(T, Loc); } } // TR 18037 does not allow fields to be declared with address spaces. if (T.getQualifiers().hasAddressSpace()) { Diag(Loc, diag::err_field_with_address_space); D.setInvalidType(); } // OpenCL 1.2 spec, s6.9 r: // The event type cannot be used to declare a structure or union field. if (LangOpts.OpenCL && T->isEventT()) { Diag(Loc, diag::err_event_t_struct_field); D.setInvalidType(); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = nullptr; LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); LookupName(Previous, S); switch (Previous.getResultKind()) { case LookupResult::Found: case LookupResult::FoundUnresolvedValue: PrevDecl = Previous.getAsSingle(); break; case LookupResult::FoundOverloaded: PrevDecl = Previous.getRepresentativeDecl(); break; case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: break; } Previous.suppressDiagnostics(); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) PrevDecl = nullptr; bool Mutable = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getLocStart(); FieldDecl *NewFD = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, InitStyle, TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl()) Record->setInvalidDecl(); if (D.getDeclSpec().isModulePrivateSpecified()) NewFD->setModulePrivate(); if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. } else if (II) { PushOnScopeChains(NewFD, S); } else Record->addDecl(NewFD); return NewFD; } /// \brief Build a new FieldDecl and check its well-formedness. /// /// This routine builds a new FieldDecl given the fields name, type, /// record, etc. \p PrevDecl should refer to any previous declaration /// with the same name and in the same scope as the field to be /// created. /// /// \returns a new FieldDecl. /// /// \todo The Declarator argument is a hack. It will be removed once FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; if (D) InvalidDecl = D->isInvalidType(); // If we receive a broken type, recover by assuming 'int' and // marking this declaration as invalid. if (T.isNull()) { InvalidDecl = true; T = Context.IntTy; } QualType EltTy = Context.getBaseElementType(T); if (!EltTy->isDependentType()) { if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) { // Fields of incomplete type force their record to be invalid. Record->setInvalidDecl(); InvalidDecl = true; } else { NamedDecl *Def; EltTy->isIncompleteType(&Def); if (Def && Def->isInvalidDecl()) { Record->setInvalidDecl(); InvalidDecl = true; } } } // OpenCL v1.2 s6.9.c: bitfields are not supported. if (BitWidth && getLangOpts().OpenCL) { Diag(Loc, diag::err_opencl_bitfields); InvalidDecl = true; } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; llvm::APSInt Oversized; TypeSourceInfo *FixedTInfo = TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, SizeIsNegative, Oversized); if (FixedTInfo) { Diag(Loc, diag::warn_illegal_constant_array_size); TInfo = FixedTInfo; T = FixedTInfo->getType(); } else { if (SizeIsNegative) Diag(Loc, diag::err_typecheck_negative_array_size); else if (Oversized.getBoolValue()) Diag(Loc, diag::err_array_too_large) << Oversized.toString(10); else Diag(Loc, diag::err_typecheck_field_variable_size); InvalidDecl = true; } } // Fields can not have abstract class types if (!InvalidDecl && RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, AbstractFieldType)) InvalidDecl = true; bool ZeroWidth = false; // If this is declared as a bit-field, check the bit-field. if (!InvalidDecl && BitWidth) { BitWidth = VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth, &ZeroWidth).get(); if (!BitWidth) { InvalidDecl = true; BitWidth = nullptr; ZeroWidth = false; } } // Check that 'mutable' is consistent with the type of the declaration. if (!InvalidDecl && Mutable) { unsigned DiagID = 0; if (T->isReferenceType()) DiagID = diag::err_mutable_reference; else if (T.isConstQualified()) DiagID = diag::err_mutable_const; if (DiagID) { SourceLocation ErrLoc = Loc; if (D && D->getDeclSpec().getStorageClassSpecLoc().isValid()) ErrLoc = D->getDeclSpec().getStorageClassSpecLoc(); Diag(ErrLoc, DiagID); Mutable = false; InvalidDecl = true; } } // C++11 [class.union]p8 (DR1460): // At most one variant member of a union may have a // brace-or-equal-initializer. if (InitStyle != ICIS_NoInit) checkDuplicateDefaultInit(*this, cast(Record), Loc); FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, BitWidth, Mutable, InitStyle); if (InvalidDecl) NewFD->setInvalidDecl(); if (PrevDecl && !isa(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); } if (!InvalidDecl && getLangOpts().CPlusPlus) { if (Record->isUnion()) { if (const RecordType *RT = EltTy->getAs()) { CXXRecordDecl* RDecl = cast(RT->getDecl()); if (RDecl->getDefinition()) { // C++ [class.union]p1: An object of a class with a non-trivial // constructor, a non-trivial copy constructor, a non-trivial // destructor, or a non-trivial copy assignment operator // cannot be a member of a union, nor can an array of such // objects. if (CheckNontrivialField(NewFD)) NewFD->setInvalidDecl(); } } // C++ [class.union]p1: If a union contains a member of reference type, // the program is ill-formed, except when compiling with MSVC extensions // enabled. if (EltTy->isReferenceType()) { Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? diag::ext_union_member_of_reference_type : diag::err_union_member_of_reference_type) << NewFD->getDeclName() << EltTy; if (!getLangOpts().MicrosoftExt) NewFD->setInvalidDecl(); } } } // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) { // FIXME: The current scope is almost... but not entirely... correct here. ProcessDeclAttributes(getCurScope(), NewFD, *D); if (NewFD->hasAttrs()) CheckAlignasUnderalignment(NewFD); } // In auto-retain/release, infer strong retension for fields of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD)) NewFD->setInvalidDecl(); if (T.isObjCGCWeak()) Diag(Loc, diag::warn_attribute_weak_on_field); NewFD->setAccess(AS); return NewFD; } bool Sema::CheckNontrivialField(FieldDecl *FD) { assert(FD); assert(getLangOpts().CPlusPlus && "valid check only for C++"); if (FD->isInvalidDecl() || FD->getType()->isDependentType()) return false; QualType EltTy = Context.getBaseElementType(FD->getType()); if (const RecordType *RT = EltTy->getAs()) { CXXRecordDecl *RDecl = cast(RT->getDecl()); if (RDecl->getDefinition()) { // We check for copy constructors before constructors // because otherwise we'll never get complaints about // copy constructors. CXXSpecialMember member = CXXInvalid; // We're required to check for any non-trivial constructors. Since the // implicit default constructor is suppressed if there are any // user-declared constructors, we just need to check that there is a // trivial default constructor and a trivial copy constructor. (We don't // worry about move constructors here, since this is a C++98 check.) if (RDecl->hasNonTrivialCopyConstructor()) member = CXXCopyConstructor; else if (!RDecl->hasTrivialDefaultConstructor()) member = CXXDefaultConstructor; else if (RDecl->hasNonTrivialCopyAssignment()) member = CXXCopyAssignment; else if (RDecl->hasNonTrivialDestructor()) member = CXXDestructor; if (member != CXXInvalid) { if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { // Objective-C++ ARC: it is an error to have a non-trivial field of // a union. However, system headers in Objective-C programs // occasionally have Objective-C lifetime objects within unions, // and rather than cause the program to fail, we make those // members unavailable. SourceLocation Loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(Loc)) { if (!FD->hasAttr()) FD->addAttr(UnavailableAttr::CreateImplicit(Context, "this system field has retaining ownership", Loc)); return false; } } Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : diag::err_illegal_union_or_anon_struct_member) << (int)FD->getParent()->isUnion() << FD->getDeclName() << member; DiagnoseNontrivial(RDecl, member); return !getLangOpts().CPlusPlus11; } } } return false; } /// TranslateIvarVisibility - Translate visibility from a token ID to an /// AST enum value. static ObjCIvarDecl::AccessControl TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { switch (ivarVisibility) { default: llvm_unreachable("Unknown visitibility kind"); case tok::objc_private: return ObjCIvarDecl::Private; case tok::objc_public: return ObjCIvarDecl::Public; case tok::objc_protected: return ObjCIvarDecl::Protected; case tok::objc_package: return ObjCIvarDecl::Package; } } /// ActOnIvar - Each ivar field of an objective-c class is passed into this /// in order to create an IvarDecl object for it. Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind Visibility) { IdentifierInfo *II = D.getIdentifier(); Expr *BitWidth = (Expr*)BitfieldWidth; SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); // FIXME: Unnamed fields can be handled in various different ways, for // example, unnamed unions inject all members into the struct namespace! TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 BitWidth = VerifyBitField(Loc, II, T, /*IsMsStruct*/false, BitWidth).get(); if (!BitWidth) D.setInvalidType(); } else { // Not a bitfield. // validate II. } if (T->isReferenceType()) { Diag(Loc, diag::err_ivar_reference_type); D.setInvalidType(); } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. else if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); D.setInvalidType(); } // Get the visibility (access control) for this ivar. ObjCIvarDecl::AccessControl ac = Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. ObjCContainerDecl *EnclosingDecl = cast(CurContext); if (!EnclosingDecl || EnclosingDecl->isInvalidDecl()) return nullptr; ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { if (LangOpts.ObjCRuntime.isFragile()) { // Case of ivar declared in an implementation. Context is that of its class. EnclosingContext = IMPDecl->getClassInterface(); assert(EnclosingContext && "Implementation has no class interface!"); } else EnclosingContext = EnclosingDecl; } else { if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); return nullptr; } } EnclosingContext = EnclosingDecl; } // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext, DeclStart, Loc, II, T, TInfo, ac, (Expr *)BitfieldWidth); if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); NewID->setInvalidDecl(); } } // Process attributes attached to the ivar. ProcessDeclAttributes(S, NewID, D); if (D.isInvalidType()) NewID->setInvalidDecl(); // In ARC, infer 'retaining' for ivars of retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewID)) NewID->setInvalidDecl(); if (D.getDeclSpec().isModulePrivateSpecified()) NewID->setModulePrivate(); if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. S->AddDecl(NewID); IdResolver.AddDecl(NewID); } if (LangOpts.ObjCRuntime.isNonFragile() && !NewID->isInvalidDecl() && isa(EnclosingDecl)) Diag(Loc, diag::warn_ivars_in_interface); return NewID; } /// ActOnLastBitfield - This routine handles synthesized bitfields rules for /// class and class extensions. For every class \@interface and class /// extension \@interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. void Sema::ActOnLastBitfield(SourceLocation DeclLoc, SmallVectorImpl &AllIvarDecls) { if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty()) return; Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast(ivarDecl); if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) return; ObjCInterfaceDecl *ID = dyn_cast(CurContext); if (!ID) { if (ObjCCategoryDecl *CD = dyn_cast(CurContext)) { if (!CD->IsClassExtension()) return; } // No need to add this to end of @implementation. else return; } // All conditions are met. Add a new bitfield to the tail end of ivars. llvm::APInt Zero(Context.getTypeSize(Context.IntTy), 0); Expr * BW = IntegerLiteral::Create(Context, Zero, Context.IntTy, DeclLoc); Ivar = ObjCIvarDecl::Create(Context, cast(CurContext), DeclLoc, DeclLoc, nullptr, Context.CharTy, Context.getTrivialTypeSourceInfo(Context.CharTy, DeclLoc), ObjCIvarDecl::Private, BW, true); AllIvarDecls.push_back(Ivar); } void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { assert(EnclosingDecl && "missing record or interface decl"); // If this is an Objective-C @implementation or category and we have // new fields here we should reset the layout of the interface since // it will now change. if (!Fields.empty() && isa(EnclosingDecl)) { ObjCContainerDecl *DC = cast(EnclosingDecl); switch (DC->getKind()) { default: break; case Decl::ObjCCategory: Context.ResetObjCLayout(cast(DC)->getClassInterface()); break; case Decl::ObjCImplementation: Context. ResetObjCLayout(cast(DC)->getClassInterface()); break; } } RecordDecl *Record = dyn_cast(EnclosingDecl); // Start counting up the number of named members; make sure to include // members of anonymous structs and unions in the total. unsigned NumNamedMembers = 0; if (Record) { for (const auto *I : Record->decls()) { if (const auto *IFD = dyn_cast(I)) if (IFD->getDeclName()) ++NumNamedMembers; } } // Verify that all the fields are okay. SmallVector RecFields; bool ARCErrReported = false; for (ArrayRef::iterator i = Fields.begin(), end = Fields.end(); i != end; ++i) { FieldDecl *FD = cast(*i); // Get the type for the field. const Type *FDTy = FD->getType().getTypePtr(); if (!FD->isAnonymousStructOrUnion()) { // Remember all fields written by the user. RecFields.push_back(FD); } // If the field is already invalid for some reason, don't emit more // diagnostics about it. if (FD->isInvalidDecl()) { EnclosingDecl->setInvalidDecl(); continue; } // C99 6.7.2.1p2: // A structure or union shall not contain a member with // incomplete or function type (hence, a structure shall not // contain an instance of itself, but may contain a pointer to // an instance of itself), except that the last member of a // structure with more than one named member may have incomplete // array type; such a structure (and any union containing, // possibly recursively, a member that is such a structure) // shall not be a member of a structure or an element of an // array. if (FDTy->isFunctionType()) { // Field declared as a function. Diag(FD->getLocation(), diag::err_field_declared_as_function) << FD->getDeclName(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } else if (FDTy->isIncompleteArrayType() && Record && ((i + 1 == Fields.end() && !Record->isUnion()) || ((getLangOpts().MicrosoftExt || getLangOpts().CPlusPlus) && (i + 1 == Fields.end() || Record->isUnion())))) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. // It will accept flexible array in union and also // as the sole element of a struct/class. unsigned DiagID = 0; if (Record->isUnion()) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_union_ms : getLangOpts().CPlusPlus ? diag::ext_flexible_array_union_gnu : diag::err_flexible_array_union; else if (Fields.size() == 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms : getLangOpts().CPlusPlus ? diag::ext_flexible_array_empty_aggregate_gnu : NumNamedMembers < 1 ? diag::err_flexible_array_empty_aggregate : 0; if (DiagID) Diag(FD->getLocation(), DiagID) << FD->getDeclName() << Record->getTagKind(); // While the layout of types that contain virtual bases is not specified // by the C++ standard, both the Itanium and Microsoft C++ ABIs place // virtual bases after the derived members. This would make a flexible // array member declared at the end of an object not adjacent to the end // of the type. if (CXXRecordDecl *RD = dyn_cast(Record)) if (RD->getNumVBases() != 0) Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) << FD->getDeclName() << Record->getTagKind(); if (!getLangOpts().C99) Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) << FD->getDeclName() << Record->getTagKind(); // If the element type has a non-trivial destructor, we would not // implicitly destroy the elements, so disallow it for now. // // FIXME: GCC allows this. We should probably either implicitly delete // the destructor of the containing class, or just allow this. QualType BaseElem = Context.getBaseElementType(FD->getType()); if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) << FD->getDeclName() << FD->getType(); FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } // Okay, we have a legal flexible array member at the end of the struct. Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { // Incomplete type FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; } else if (const RecordType *FDTTy = FDTy->getAs()) { if (Record && FDTTy->getDecl()->hasFlexibleArrayMember()) { // A type which contains a flexible array member is considered to be a // flexible array member. Record->setHasFlexibleArrayMember(true); if (!Record->isUnion()) { // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. if (i + 1 != Fields.end()) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { // We support flexible arrays at the end of structs in // other structs as an extension. Diag(FD->getLocation(), diag::ext_flexible_array_in_struct) << FD->getDeclName(); } } } if (isa(EnclosingDecl) && RequireNonAbstractType(FD->getLocation(), FD->getType(), diag::err_abstract_type_in_decl, AbstractIvarType)) { // Ivars can not have abstract class types FD->setInvalidDecl(); } if (Record && FDTTy->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); if (Record && FDTTy->getDecl()->hasVolatileMember()) Record->setHasVolatileMember(true); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(FD->getLocation(), "*"); QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); } else if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported && (!getLangOpts().CPlusPlus || Record->isUnion())) { // It's an error in ARC if a field has lifetime. // We don't want to report this in a system header, though, // so we just make the field unavailable. // FIXME: that's really not sufficient; we need to make the type // itself invalid to, say, initialize or copy. QualType T = FD->getType(); Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime(); if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) { SourceLocation loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(loc)) { if (!FD->hasAttr()) { FD->addAttr(UnavailableAttr::CreateImplicit(Context, "this system field has retaining ownership", loc)); } } else { Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag) << T->isBlockPointerType() << Record->getTagKind(); } ARCErrReported = true; } } else if (getLangOpts().ObjC1 && getLangOpts().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { if (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong()) Record->setHasObjectMember(true); else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); if (BaseType->isRecordType() && BaseType->getAs()->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) Record->setHasObjectMember(true); } } if (Record && FD->getType().isVolatileQualified()) Record->setHasVolatileMember(true); // Keep track of the number of named members. if (FD->getIdentifier()) ++NumNamedMembers; } // Okay, we successfully defined 'Record'. if (Record) { bool Completed = false; if (CXXRecordDecl *CXXRecord = dyn_cast(Record)) { if (!CXXRecord->isInvalidDecl()) { // Set access bits correctly on the directly-declared conversions. for (CXXRecordDecl::conversion_iterator I = CXXRecord->conversion_begin(), E = CXXRecord->conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); if (!CXXRecord->isDependentType()) { if (CXXRecord->hasUserDeclaredDestructor()) { // Adjust user-defined destructor exception spec. if (getLangOpts().CPlusPlus11) AdjustDestructorExceptionSpec(CXXRecord, CXXRecord->getDestructor()); } // Add any implicitly-declared members to this class. AddImplicitlyDeclaredMembersToClass(CXXRecord); // If we have virtual base classes, we may end up finding multiple // final overriders for a given virtual function. Check for this // problem now. if (CXXRecord->getNumVBases()) { CXXFinalOverriderMap FinalOverriders; CXXRecord->getFinalOverriders(FinalOverriders); for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), MEnd = FinalOverriders.end(); M != MEnd; ++M) { for (OverridingMethods::iterator SO = M->second.begin(), SOEnd = M->second.end(); SO != SOEnd; ++SO) { assert(SO->second.size() > 0 && "Virtual function without overridding functions?"); if (SO->second.size() == 1) continue; // C++ [class.virtual]p2: // In a derived class, if a virtual member function of a base // class subobject has more than one final overrider the // program is ill-formed. Diag(Record->getLocation(), diag::err_multiple_final_overriders) << (const NamedDecl *)M->first << Record; Diag(M->first->getLocation(), diag::note_overridden_virtual_function); for (OverridingMethods::overriding_iterator OM = SO->second.begin(), OMEnd = SO->second.end(); OM != OMEnd; ++OM) Diag(OM->Method->getLocation(), diag::note_final_overrider) << (const NamedDecl *)M->first << OM->Method->getParent(); Record->setInvalidDecl(); } } CXXRecord->completeDefinition(&FinalOverriders); Completed = true; } } } } if (!Completed) Record->completeDefinition(); if (Record->hasAttrs()) { CheckAlignasUnderalignment(Record); if (const MSInheritanceAttr *IA = Record->getAttr()) checkMSInheritanceAttrOnDefinition(cast(Record), IA->getRange(), IA->getBestCase(), IA->getSemanticSpelling()); } // Check if the structure/union declaration is a type that can have zero // size in C. For C this is a language extension, for C++ it may cause // compatibility problems. bool CheckForZeroSize; if (!getLangOpts().CPlusPlus) { CheckForZeroSize = true; } else { // For C++ filter out types that cannot be referenced in C code. CXXRecordDecl *CXXRecord = cast(Record); CheckForZeroSize = CXXRecord->getLexicalDeclContext()->isExternCContext() && !CXXRecord->isDependentType() && CXXRecord->isCLike(); } if (CheckForZeroSize) { bool ZeroSize = true; bool IsEmpty = true; unsigned NonBitFields = 0; for (RecordDecl::field_iterator I = Record->field_begin(), E = Record->field_end(); (NonBitFields == 0 || ZeroSize) && I != E; ++I) { IsEmpty = false; if (I->isUnnamedBitfield()) { if (I->getBitWidthValue(Context) > 0) ZeroSize = false; } else { ++NonBitFields; QualType FieldType = I->getType(); if (FieldType->isIncompleteType() || !Context.getTypeSizeInChars(FieldType).isZero()) ZeroSize = false; } } // Empty structs are an extension in C (C99 6.7.2.1p7). They are // allowed in C++, but warn if its declaration is inside // extern "C" block. if (ZeroSize) { Diag(RecLoc, getLangOpts().CPlusPlus ? diag::warn_zero_size_struct_union_in_extern_c : diag::warn_zero_size_struct_union_compat) << IsEmpty << Record->isUnion() << (NonBitFields > 1); } // Structs without named members are extension in C (C99 6.7.2.1p7), // but are accepted by GCC. if (NonBitFields == 0 && !getLangOpts().CPlusPlus) { Diag(RecLoc, IsEmpty ? diag::ext_empty_struct_union : diag::ext_no_named_members_in_struct_union) << Record->isUnion(); } } } else { ObjCIvarDecl **ClsFields = reinterpret_cast(RecFields.data()); if (ObjCInterfaceDecl *ID = dyn_cast(EnclosingDecl)) { ID->setEndOfDefinitionLoc(RBrac); // Add ivar's to class's DeclContext. for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { ClsFields[i]->setLexicalDeclContext(ID); ID->addDecl(ClsFields[i]); } // Must enforce the rule that ivars in the base classes may not be // duplicates. if (ID->getSuperClass()) DiagnoseDuplicateIvars(ID, ID->getSuperClass()); } else if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); for (unsigned I = 0, N = RecFields.size(); I != N; ++I) // Ivar declared in @implementation never belongs to the implementation. // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); IMPDecl->setIvarLBraceLoc(LBrac); IMPDecl->setIvarRBraceLoc(RBrac); } else if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { // case of ivars in class extension; all other cases have been // reported as errors elsewhere. // FIXME. Class extension does not have a LocEnd field. // CDecl->setLocEnd(RBrac); // Add ivar's to class extension's DeclContext. // Diagnose redeclaration of private ivars. ObjCInterfaceDecl *IDecl = CDecl->getClassInterface(); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { if (IDecl) { if (const ObjCIvarDecl *ClsIvar = IDecl->getIvarDecl(ClsFields[i]->getIdentifier())) { Diag(ClsFields[i]->getLocation(), diag::err_duplicate_ivar_declaration); Diag(ClsIvar->getLocation(), diag::note_previous_definition); continue; } for (const auto *Ext : IDecl->known_extensions()) { if (const ObjCIvarDecl *ClsExtIvar = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) { Diag(ClsFields[i]->getLocation(), diag::err_duplicate_ivar_declaration); Diag(ClsExtIvar->getLocation(), diag::note_previous_definition); continue; } } } ClsFields[i]->setLexicalDeclContext(CDecl); CDecl->addDecl(ClsFields[i]); } CDecl->setIvarLBraceLoc(LBrac); CDecl->setIvarRBraceLoc(RBrac); } } if (Attr) ProcessDeclAttributeList(S, Record, Attr); } /// \brief Determine whether the given integral value is representable within /// the given type T. static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, QualType T) { assert(T->isIntegralType(Context) && "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) { if (T->isSignedIntegerOrEnumerationType()) --BitWidth; return Value.getActiveBits() <= BitWidth; } return Value.getMinSignedBits() <= BitWidth; } // \brief Given an integral type, return the next larger integral type // (or a NULL type of no such type exists). static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { // FIXME: Int128/UInt128 support, which also needs to be introduced into // enum checking below. assert(T->isIntegralType(Context) && "Integral type required!"); const unsigned NumTypes = 4; QualType SignedIntegralTypes[NumTypes] = { Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy }; QualType UnsignedIntegralTypes[NumTypes] = { Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy }; unsigned BitWidth = Context.getTypeSize(T); QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes : UnsignedIntegralTypes; for (unsigned I = 0; I != NumTypes; ++I) if (Context.getTypeSize(Types[I]) > BitWidth) return Types[I]; return QualType(); } EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *Val) { unsigned IntWidth = Context.getTargetInfo().getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; if (Val && DiagnoseUnexpandedParameterPack(Val, UPPC_EnumeratorValue)) Val = nullptr; if (Val) Val = DefaultLvalueConversion(Val).get(); if (Val) { if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { SourceLocation ExpLoc; if (getLangOpts().CPlusPlus11 && Enum->isFixed() && !getLangOpts().MSVCCompat) { // C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the // constant-expression in the enumerator-definition shall be a converted // constant expression of the underlying type. EltTy = Enum->getIntegerType(); ExprResult Converted = CheckConvertedConstantExpression(Val, EltTy, EnumVal, CCEK_Enumerator); if (Converted.isInvalid()) Val = nullptr; else Val = Converted.get(); } else if (!Val->isValueDependent() && !(Val = VerifyIntegerConstantExpression(Val, &EnumVal).get())) { // C99 6.7.2.2p2: Make sure we have an integer constant expression. } else { if (Enum->isFixed()) { EltTy = Enum->getIntegerType(); // In Obj-C and Microsoft mode, require the enumeration value to be // representable in the underlying type of the enumeration. In C++11, // we perform a non-narrowing conversion as part of converted constant // expression checking. if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { if (getLangOpts().MSVCCompat) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); } else Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; } else Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); } else if (getLangOpts().CPlusPlus) { // C++11 [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // - If an initializer is specified for an enumerator, the // initializing value has the same type as the expression. EltTy = Val->getType(); } else { // C99 6.7.2.2p2: // The expression that defines the value of an enumeration constant // shall be an integer constant expression that has a value // representable as an int. // Complain if the value is not representable in an int. if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) Diag(IdLoc, diag::ext_enum_value_not_int) << EnumVal.toString(10) << Val->getSourceRange() << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { // Force the type of the expression to 'int'. Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).get(); } EltTy = Val->getType(); } } } } if (!Val) { if (Enum->isDependentType()) EltTy = Context.DependentTy; else if (!LastEnumConst) { // C++0x [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // - If no initializer is specified for the first enumerator, the // initializing value has an unspecified integral type. // // GCC uses 'int' for its unspecified integral type, as does // C99 6.7.2.2p3. if (Enum->isFixed()) { EltTy = Enum->getIntegerType(); } else { EltTy = Context.IntTy; } } else { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); ++EnumVal; EltTy = LastEnumConst->getType(); // Check for overflow on increment. if (EnumVal < LastEnumConst->getInitVal()) { // C++0x [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: // // - Otherwise the type of the initializing value is the same as // the type of the initializing value of the preceding enumerator // unless the incremented value is not representable in that type, // in which case the type is an unspecified integral type // sufficient to contain the incremented value. If no such type // exists, the program is ill-formed. QualType T = getNextLargerIntegralType(Context, EltTy); if (T.isNull() || Enum->isFixed()) { // There is no integral type larger enough to represent this // value. Complain, then allow the value to wrap around. EnumVal = LastEnumConst->getInitVal(); EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2); ++EnumVal; if (Enum->isFixed()) // When the underlying type is fixed, this is ill-formed. Diag(IdLoc, diag::err_enumerator_wrapped) << EnumVal.toString(10) << EltTy; else Diag(IdLoc, diag::ext_enumerator_increment_too_large) << EnumVal.toString(10); } else { EltTy = T; } // Retrieve the last enumerator's value, extent that type to the // type that is supposed to be large enough to represent the incremented // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, // which in C99 means that the enumerator value is not representable in // an int (C99 6.7.2.2p2). However, we support GCC's extension that // permits enumerator values that are representable in some larger // integral type. if (!getLangOpts().CPlusPlus && !T.isNull()) Diag(IdLoc, diag::warn_enum_value_overflow); } else if (!getLangOpts().CPlusPlus && !isRepresentableIntegerValue(Context, EnumVal, EltTy)) { // Enforce C99 6.7.2.2p2 even when we compute the next value. Diag(IdLoc, diag::ext_enum_value_not_int) << EnumVal.toString(10) << 1; } } } if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal = EnumVal.extOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); } return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, Val, EnumVal); } Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attr, SourceLocation EqualLoc, Expr *Val) { EnumDecl *TheEnumDecl = cast(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null(lastEnumConst); // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. S = getNonFieldDeclScope(S); // Verify that there isn't already something declared with this name in this // scope. NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = nullptr; } if (PrevDecl) { // When in C++, we may get a TagDecl with the same name; in this case the // enum constant will 'hide' the tag. assert((getLangOpts().CPlusPlus || !isa(PrevDecl)) && "Received TagDecl when not in C++!"); if (!isa(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) { if (isa(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; else Diag(IdLoc, diag::err_redefinition) << Id; Diag(PrevDecl->getLocation(), diag::note_previous_definition); return nullptr; } } // C++ [class.mem]p15: // If T is the name of a class, then each of the following shall have a name // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type if (CXXRecordDecl *Record = dyn_cast( TheEnumDecl->getDeclContext()->getRedeclContext())) if (!TheEnumDecl->isScoped() && Record->getIdentifier() && Record->getIdentifier() == Id) Diag(IdLoc, diag::err_member_name_of_class) << Id; EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); if (New) { // Process attributes. if (Attr) ProcessDeclAttributeList(S, New, Attr); // Register this decl in the current scope stack. New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); } ActOnDocumentableDecl(New); return New; } // Returns true when the enum initial expression does not trigger the // duplicate enum warning. A few common cases are exempted as follows: // Element2 = Element1 // Element2 = Element1 + 1 // Element2 = Element1 - 1 // Where Element2 and Element1 are from the same enum. static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) { Expr *InitExpr = ECD->getInitExpr(); if (!InitExpr) return true; InitExpr = InitExpr->IgnoreImpCasts(); if (BinaryOperator *BO = dyn_cast(InitExpr)) { if (!BO->isAdditiveOp()) return true; IntegerLiteral *IL = dyn_cast(BO->getRHS()); if (!IL) return true; if (IL->getValue() != 1) return true; InitExpr = BO->getLHS(); } // This checks if the elements are from the same enum. DeclRefExpr *DRE = dyn_cast(InitExpr); if (!DRE) return true; EnumConstantDecl *EnumConstant = dyn_cast(DRE->getDecl()); if (!EnumConstant) return true; if (cast(TagDecl::castFromDeclContext(ECD->getDeclContext())) != Enum) return true; return false; } struct DupKey { int64_t val; bool isTombstoneOrEmptyKey; DupKey(int64_t val, bool isTombstoneOrEmptyKey) : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {} }; static DupKey GetDupKey(const llvm::APSInt& Val) { return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(), false); } struct DenseMapInfoDupKey { static DupKey getEmptyKey() { return DupKey(0, true); } static DupKey getTombstoneKey() { return DupKey(1, true); } static unsigned getHashValue(const DupKey Key) { return (unsigned)(Key.val * 37); } static bool isEqual(const DupKey& LHS, const DupKey& RHS) { return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey && LHS.val == RHS.val; } }; // Emits a warning when an element is implicitly set a value that // a previous element has already been set to. static void CheckForDuplicateEnumValues(Sema &S, ArrayRef Elements, EnumDecl *Enum, QualType EnumType) { if (S.Diags.isIgnored(diag::warn_duplicate_enum_values, Enum->getLocation())) return; // Avoid anonymous enums if (!Enum->getIdentifier()) return; // Only check for small enums. if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64) return; typedef SmallVector ECDVector; typedef SmallVector DuplicatesVector; typedef llvm::PointerUnion DeclOrVector; typedef llvm::DenseMap ValueToVectorMap; DuplicatesVector DupVector; ValueToVectorMap EnumMap; // Populate the EnumMap with all values represented by enum constants without // an initialier. for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); // Null EnumConstantDecl means a previous diagnostic has been emitted for // this constant. Skip this enum since it may be ill-formed. if (!ECD) { return; } if (ECD->getInitExpr()) continue; DupKey Key = GetDupKey(ECD->getInitVal()); DeclOrVector &Entry = EnumMap[Key]; // First time encountering this value. if (Entry.isNull()) Entry = ECD; } // Create vectors for any values that has duplicates. for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast(Elements[i]); if (!ValidDuplicateEnum(ECD, Enum)) continue; DupKey Key = GetDupKey(ECD->getInitVal()); DeclOrVector& Entry = EnumMap[Key]; if (Entry.isNull()) continue; if (EnumConstantDecl *D = Entry.dyn_cast()) { // Ensure constants are different. if (D == ECD) continue; // Create new vector and push values onto it. ECDVector *Vec = new ECDVector(); Vec->push_back(D); Vec->push_back(ECD); // Update entry to point to the duplicates vector. Entry = Vec; // Store the vector somewhere we can consult later for quick emission of // diagnostics. DupVector.push_back(Vec); continue; } ECDVector *Vec = Entry.get(); // Make sure constants are not added more than once. if (*Vec->begin() == ECD) continue; Vec->push_back(ECD); } // Emit diagnostics. for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(), DupVectorEnd = DupVector.end(); DupVectorIter != DupVectorEnd; ++DupVectorIter) { ECDVector *Vec = *DupVectorIter; assert(Vec->size() > 1 && "ECDVector should have at least 2 elements."); // Emit warning for one enum constant. ECDVector::iterator I = Vec->begin(); S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values) << (*I)->getName() << (*I)->getInitVal().toString(10) << (*I)->getSourceRange(); ++I; // Emit one note for each of the remaining enum constants with // the same value. for (ECDVector::iterator E = Vec->end(); I != E; ++I) S.Diag((*I)->getLocation(), diag::note_duplicate_element) << (*I)->getName() << (*I)->getInitVal().toString(10) << (*I)->getSourceRange(); delete Vec; } } void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, ArrayRef Elements, Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); if (Attr) ProcessDeclAttributeList(S, Enum, Attr); if (Enum->isDependentType()) { for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; ECD->setType(EnumType); } Enum->completeDefinition(Context.DependentTy, Context.DependentTy, 0, 0); return; } // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); unsigned CharWidth = Context.getTargetInfo().getCharWidth(); unsigned ShortWidth = Context.getTargetInfo().getShortWidth(); // Verify that all the values are okay, compute the size of the values, and // reverse the list. unsigned NumNegativeBits = 0; unsigned NumPositiveBits = 0; // Keep track of whether all elements have type int. bool AllElementsInt = true; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. const llvm::APSInt &InitVal = ECD->getInitVal(); // Keep track of the size of positive and negative values. if (InitVal.isUnsigned() || InitVal.isNonNegative()) NumPositiveBits = std::max(NumPositiveBits, (unsigned)InitVal.getActiveBits()); else NumNegativeBits = std::max(NumNegativeBits, (unsigned)InitVal.getMinSignedBits()); // Keep track of whether every enum element has type int (very commmon). if (AllElementsInt) AllElementsInt = ECD->getType() == Context.IntTy; } // Figure out the type that should be used for this enum. QualType BestType; unsigned BestWidth; // C++0x N3000 [conv.prom]p3: // An rvalue of an unscoped enumeration type whose underlying // type is not fixed can be converted to an rvalue of the first // of the following types that can represent all the values of // the enumeration: int, unsigned int, long int, unsigned long // int, long long int, or unsigned long long int. // C99 6.4.4.3p2: // An identifier declared as an enumeration constant has type int. // The C99 rule is modified by a gcc extension QualType BestPromotionType; bool Packed = Enum->hasAttr(); // -fshort-enums is the equivalent to specifying the packed attribute on all // enum definitions. if (LangOpts.ShortEnums) Packed = true; if (Enum->isFixed()) { BestType = Enum->getIntegerType(); if (BestType->isPromotableIntegerType()) BestPromotionType = Context.getPromotedIntegerType(BestType); else BestPromotionType = BestType; // We don't need to set BestWidth, because BestType is going to be the type // of the enumerators, but we do anyway because otherwise some compilers // warn that it might be used uninitialized. BestWidth = CharWidth; } else if (NumNegativeBits) { // If there is a negative value, figure out the smallest integer type (of // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) { BestType = Context.SignedCharTy; BestWidth = CharWidth; } else if (Packed && NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) { BestType = Context.ShortTy; BestWidth = ShortWidth; } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.getTargetInfo().getLongWidth(); if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; } else { BestWidth = Context.getTargetInfo().getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) Diag(Enum->getLocation(), diag::ext_enum_too_large); BestType = Context.LongLongTy; } } BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { // If there is no negative value, figure out the smallest type that fits // all of the enumerator values. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { BestType = Context.UnsignedCharTy; BestPromotionType = Context.IntTy; BestWidth = CharWidth; } else if (Packed && NumPositiveBits <= ShortWidth) { BestType = Context.UnsignedShortTy; BestPromotionType = Context.IntTy; BestWidth = ShortWidth; } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedIntTy : Context.IntTy; } else if (NumPositiveBits <= (BestWidth = Context.getTargetInfo().getLongWidth())) { BestType = Context.UnsignedLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedLongTy : Context.LongTy; } else { BestWidth = Context.getTargetInfo().getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; BestPromotionType = (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus) ? Context.UnsignedLongLongTy : Context.LongLongTy; } } // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. // Standard C says the enumerators have int type, but we allow, as an // extension, the enumerators to be larger than int size. If each // enumerator value fits in an int, type it as an int, otherwise type it the // same as the enumerator decl itself. This means that in "enum { X = 1U }" // that X has type 'int', not 'unsigned'. // Determine whether the value fits into an int. llvm::APSInt InitVal = ECD->getInitVal(); // If it fits into an integer type, force it. Otherwise force it to match // the enum decl type. QualType NewTy; unsigned NewWidth; bool NewSign; if (!getLangOpts().CPlusPlus && !Enum->isFixed() && isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) { NewTy = Context.IntTy; NewWidth = IntWidth; NewSign = true; } else if (ECD->getType() == BestType) { // Already the right type! if (getLangOpts().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its // enumeration. ECD->setType(EnumType); continue; } else { NewTy = BestType; NewWidth = BestWidth; NewSign = BestType->isSignedIntegerOrEnumerationType(); } // Adjust the APSInt value. InitVal = InitVal.extOrTrunc(NewWidth); InitVal.setIsSigned(NewSign); ECD->setInitVal(InitVal); // Adjust the Expr initializer and type. if (ECD->getInitExpr() && !Context.hasSameType(NewTy, ECD->getInitExpr()->getType())) ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, CK_IntegralCast, ECD->getInitExpr(), /*base paths*/ nullptr, VK_RValue)); if (getLangOpts().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its // enumeration. ECD->setType(EnumType); else ECD->setType(NewTy); } Enum->completeDefinition(BestType, BestPromotionType, NumPositiveBits, NumNegativeBits); CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType); // Now that the enum type is defined, ensure it's not been underaligned. if (Enum->hasAttrs()) CheckAlignasUnderalignment(Enum); } Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, SourceLocation StartLoc, SourceLocation EndLoc) { StringLiteral *AsmString = cast(expr); FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext, AsmString, StartLoc, EndLoc); CurContext->addDecl(New); return New; } static void checkModuleImportContext(Sema &S, Module *M, SourceLocation ImportLoc, DeclContext *DC) { if (auto *LSD = dyn_cast(DC)) { switch (LSD->getLanguage()) { case LinkageSpecDecl::lang_c: if (!M->IsExternC) { S.Diag(ImportLoc, diag::err_module_import_in_extern_c) << M->getFullModuleName(); S.Diag(LSD->getLocStart(), diag::note_module_import_in_extern_c); return; } break; case LinkageSpecDecl::lang_cxx: break; } DC = LSD->getParent(); } while (isa(DC)) DC = DC->getParent(); if (!isa(DC)) { S.Diag(ImportLoc, diag::err_module_import_not_at_top_level) << M->getFullModuleName() << DC; S.Diag(cast(DC)->getLocStart(), diag::note_module_import_not_at_top_level) << DC; } } DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path) { Module *Mod = getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, /*IsIncludeDirective=*/false); if (!Mod) return true; checkModuleImportContext(*this, Mod, ImportLoc, CurContext); // FIXME: we should support importing a submodule within a different submodule // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule) Diag(ImportLoc, diag::err_module_self_import) << Mod->getFullModuleName() << getLangOpts().CurrentModule; else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule) Diag(ImportLoc, diag::err_module_import_in_implementation) << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule; SmallVector IdentifierLocs; Module *ModCheck = Mod; for (unsigned I = 0, N = Path.size(); I != N; ++I) { // If we've run out of module parents, just drop the remaining identifiers. // We need the length to be consistent. if (!ModCheck) break; ModCheck = ModCheck->Parent; IdentifierLocs.push_back(Path[I].second); } ImportDecl *Import = ImportDecl::Create(Context, Context.getTranslationUnitDecl(), AtLoc.isValid()? AtLoc : ImportLoc, Mod, IdentifierLocs); Context.getTranslationUnitDecl()->addDecl(Import); return Import; } void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext); // FIXME: Should we synthesize an ImportDecl here? getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc, /*Complain=*/true); } void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod) { // Bail if we're not allowed to implicitly import a module here. if (isSFINAEContext() || !getLangOpts().ModulesErrorRecovery) return; // Create the implicit import declaration. TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, Loc, Mod, Loc); TU->addDecl(ImportD); Consumer.HandleImplicitImportDecl(ImportD); // Make the module visible. getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc, /*Complain=*/false); } void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); AsmLabelAttr *Attr = ::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName(), 0); if (PrevDecl) PrevDecl->addAttr(Attr); else (void)ExtnameUndeclaredIdentifiers.insert( std::pair(Name, Attr)); } void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc)); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair (Name, WeakInfo((IdentifierInfo*)nullptr, NameLoc))); } } void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc, LookupOrdinaryName); WeakInfo W = WeakInfo(Name, NameLoc); if (PrevDecl) { if (!PrevDecl->hasAttr()) if (NamedDecl *ND = dyn_cast(PrevDecl)) DeclApplyPragmaWeak(TUScope, ND, W); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair(AliasName, W)); } } Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null(CurContext)); } AvailabilityResult Sema::getCurContextAvailability() const { const Decl *D = cast(getCurObjCLexicalContext()); // If we are within an Objective-C method, we should consult // both the availability of the method as well as the // enclosing class. If the class is (say) deprecated, // the entire method is considered deprecated from the // purpose of checking if the current context is deprecated. if (const ObjCMethodDecl *MD = dyn_cast(D)) { AvailabilityResult R = MD->getAvailability(); if (R != AR_Available) return R; D = MD->getClassInterface(); } // If we are within an Objective-c @implementation, it // gets the same availability context as the @interface. else if (const ObjCImplementationDecl *ID = dyn_cast(D)) { D = ID->getClassInterface(); } // Recover from user error. return D ? D->getAvailability() : AR_Available; } Index: vendor/clang/dist/lib/Sema/SemaLookup.cpp =================================================================== --- vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 278753) +++ vendor/clang/dist/lib/Sema/SemaLookup.cpp (revision 278754) @@ -1,4577 +1,4587 @@ //===--------------------- SemaLookup.cpp - Name Lookup ------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements name lookup for C, C++, Objective-C, and // Objective-C++. // //===----------------------------------------------------------------------===// #include "clang/Sema/Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include #include #include #include #include using namespace clang; using namespace sema; namespace { class UnqualUsingEntry { const DeclContext *Nominated; const DeclContext *CommonAncestor; public: UnqualUsingEntry(const DeclContext *Nominated, const DeclContext *CommonAncestor) : Nominated(Nominated), CommonAncestor(CommonAncestor) { } const DeclContext *getCommonAncestor() const { return CommonAncestor; } const DeclContext *getNominatedNamespace() const { return Nominated; } // Sort by the pointer value of the common ancestor. struct Comparator { bool operator()(const UnqualUsingEntry &L, const UnqualUsingEntry &R) { return L.getCommonAncestor() < R.getCommonAncestor(); } bool operator()(const UnqualUsingEntry &E, const DeclContext *DC) { return E.getCommonAncestor() < DC; } bool operator()(const DeclContext *DC, const UnqualUsingEntry &E) { return DC < E.getCommonAncestor(); } }; }; /// A collection of using directives, as used by C++ unqualified /// lookup. class UnqualUsingDirectiveSet { typedef SmallVector ListTy; ListTy list; llvm::SmallPtrSet visited; public: UnqualUsingDirectiveSet() {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { // C++ [namespace.udir]p1: // During unqualified name lookup, the names appear as if they // were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. DeclContext *InnermostFileDC = InnermostFileScope->getEntity(); assert(InnermostFileDC && InnermostFileDC->isFileContext()); for (; S; S = S->getParent()) { // C++ [namespace.udir]p1: // A using-directive shall not appear in class scope, but may // appear in namespace scope or in block scope. DeclContext *Ctx = S->getEntity(); if (Ctx && Ctx->isFileContext()) { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { for (auto *I : S->using_directives()) visit(I, InnermostFileDC); } } } // Visits a context and collect all of its using directives // recursively. Treats all using directives as if they were // declared in the context. // // A given context is only every visited once, so it is important // that contexts be visited from the inside out in order to get // the effective DCs right. void visit(DeclContext *DC, DeclContext *EffectiveDC) { if (!visited.insert(DC).second) return; addUsingDirectives(DC, EffectiveDC); } // Visits a using directive and collects all of its using // directives recursively. Treats all using directives as if they // were declared in the effective DC. void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { DeclContext *NS = UD->getNominatedNamespace(); if (!visited.insert(NS).second) return; addUsingDirective(UD, EffectiveDC); addUsingDirectives(NS, EffectiveDC); } // Adds all the using directives in a context (and those nominated // by its using directives, transitively) as if they appeared in // the given effective context. void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { SmallVector queue; while (true) { for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); if (visited.insert(NS).second) { addUsingDirective(UD, EffectiveDC); queue.push_back(NS); } } if (queue.empty()) return; DC = queue.pop_back_val(); } } // Add a using directive as if it had been declared in the given // context. This helps implement C++ [namespace.udir]p3: // The using-directive is transitive: if a scope contains a // using-directive that nominates a second namespace that itself // contains using-directives, the effect is as if the // using-directives from the second namespace also appeared in // the first. void addUsingDirective(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { // Find the common ancestor between the effective context and // the nominated namespace. DeclContext *Common = UD->getNominatedNamespace(); while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); Common = Common->getPrimaryContext(); list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } void done() { std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); } typedef ListTy::const_iterator const_iterator; const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } std::pair getNamespacesFor(DeclContext *DC) const { return std::equal_range(begin(), end(), DC->getPrimaryContext(), UnqualUsingEntry::Comparator()); } }; } // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. static inline unsigned getIDNS(Sema::LookupNameKind NameKind, bool CPlusPlus, bool Redeclaration) { unsigned IDNS = 0; switch (NameKind) { case Sema::LookupObjCImplicitSelfParam: case Sema::LookupOrdinaryName: case Sema::LookupRedeclarationWithLinkage: case Sema::LookupLocalFriendName: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } if (Redeclaration) IDNS |= Decl::IDNS_LocalExtern; break; case Sema::LookupOperatorName: // Operator lookup is its own crazy thing; it is not the same // as (e.g.) looking up an operator name for redeclaration. assert(!Redeclaration && "cannot do redeclaration operator lookup"); IDNS = Decl::IDNS_NonMemberOperator; break; case Sema::LookupTagName: if (CPlusPlus) { IDNS = Decl::IDNS_Type; // When looking for a redeclaration of a tag name, we add: // 1) TagFriend to find undeclared friend decls // 2) Namespace because they can't "overload" with tag decls. // 3) Tag because it includes class templates, which can't // "overload" with tag decls. if (Redeclaration) IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace; } else { IDNS = Decl::IDNS_Tag; } break; case Sema::LookupLabel: IDNS = Decl::IDNS_Label; break; case Sema::LookupMemberName: IDNS = Decl::IDNS_Member; if (CPlusPlus) IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; break; case Sema::LookupNestedNameSpecifierName: IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace; break; case Sema::LookupNamespaceName: IDNS = Decl::IDNS_Namespace; break; case Sema::LookupUsingDeclName: assert(Redeclaration && "should only be used for redecl lookup"); IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend | Decl::IDNS_LocalExtern; break; case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol | Decl::IDNS_Type; break; } return IDNS; } void LookupResult::configure() { IDNS = getIDNS(LookupKind, getSema().getLangOpts().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation // operators, make sure that the implicitly-declared new and delete // operators can be found. switch (NameInfo.getName().getCXXOverloadedOperator()) { case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: getSema().DeclareGlobalNewDelete(); break; default: break; } // Compiler builtins are always visible, regardless of where they end // up being declared. if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { if (unsigned BuiltinID = Id->getBuiltinID()) { if (!getSema().Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) AllowHidden = true; } } } bool LookupResult::sanity() const { // This function is never called by NDEBUG builds. assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || (Decls.size() == 1 && isa((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || Ambiguity == AmbiguousBaseSubobjectTypes))); assert((Paths != nullptr) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); return true; } // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } /// Get a representative context for a declaration such that two declarations /// will have the same context if they were found within the same scope. static DeclContext *getContextForScopeMatching(Decl *D) { // For function-local declarations, use that function as the context. This // doesn't account for scopes within the function; the caller must deal with // those. DeclContext *DC = D->getLexicalDeclContext(); if (DC->isFunctionOrMethod()) return DC; // Otherwise, look at the semantic context of the declaration. The // declaration must have been found there. return D->getDeclContext()->getRedeclContext(); } /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); return; } // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); if (isa(D)) ResultKind = FoundOverloaded; else if (isa(D)) ResultKind = FoundUnresolvedValue; return; } // Don't do any extra resolution if we've already resolved as ambiguous. if (ResultKind == Ambiguous) return; llvm::SmallPtrSet Unique; llvm::SmallPtrSet UniqueTypes; bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); D = cast(D->getCanonicalDecl()); // Ignore an invalid declaration unless it's the only one left. if (D->isInvalidDecl() && I < N-1) { Decls[I] = Decls[--N]; continue; } // Redeclarations of types via typedef can occur both within a scope // and, through using declarations and directives, across scopes. There is // no ambiguity if they all refer to the same type, so unique based on the // canonical type. if (TypeDecl *TD = dyn_cast(D)) { if (!TD->getDeclContext()->isRecord()) { QualType T = getSema().Context.getTypeDeclType(TD); if (!UniqueTypes.insert(getSema().Context.getCanonicalType(T)).second) { // The type is not unique; pull something off the back and continue // at this index. Decls[I] = Decls[--N]; continue; } } } if (!Unique.insert(D).second) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; continue; } // Otherwise, do some decl type analysis and then continue. if (isa(D)) { HasUnresolved = true; } else if (isa(D)) { if (HasTag) Ambiguous = true; UniqueTagIndex = I; HasTag = true; } else if (isa(D)) { HasFunction = true; HasFunctionTemplate = true; } else if (isa(D)) { HasFunction = true; } else { if (HasNonFunction) Ambiguous = true; HasNonFunction = true; } I++; } // C++ [basic.scope.hiding]p2: // A class name or enumeration name can be hidden by the name of // an object, function, or enumerator declared in the same // scope. If a class or enumeration name and an object, function, // or enumerator are declared in the same scope (in any order) // with the same name, the class or enumeration name is hidden // wherever the object, function, or enumerator name is visible. // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) if (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction || HasUnresolved)) { if (getContextForScopeMatching(Decls[UniqueTagIndex])->Equals( getContextForScopeMatching(Decls[UniqueTagIndex ? 0 : N - 1]))) Decls[UniqueTagIndex] = Decls[--N]; else Ambiguous = true; } Decls.set_size(N); if (HasNonFunction && (HasFunction || HasUnresolved)) Ambiguous = true; if (Ambiguous) setAmbiguous(LookupResult::AmbiguousReference); else if (HasUnresolved) ResultKind = LookupResult::FoundUnresolvedValue; else if (N > 1 || HasFunctionTemplate) ResultKind = LookupResult::FoundOverloaded; else ResultKind = LookupResult::Found; } void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::const_paths_iterator I, E; for (I = P.begin(), E = P.end(); I != E; ++I) for (DeclContext::lookup_iterator DI = I->Decls.begin(), DE = I->Decls.end(); DI != DE; ++DI) addDecl(*DI); } void LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); resolveKind(); setAmbiguous(AmbiguousBaseSubobjects); } void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); resolveKind(); setAmbiguous(AmbiguousBaseSubobjectTypes); } void LookupResult::print(raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; for (iterator I = begin(), E = end(); I != E; ++I) { Out << "\n"; (*I)->print(Out, 2); } } /// \brief Lookup a builtin function, when name lookup would otherwise /// fail. static bool LookupBuiltin(Sema &S, LookupResult &R) { Sema::LookupNameKind NameKind = R.getLookupKind(); // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. if (NameKind == Sema::LookupOrdinaryName || NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { if (S.getLangOpts().CPlusPlus11 && S.getLangOpts().GNUMode && II == S.getFloat128Identifier()) { // libstdc++4.7's type_traits expects type __float128 to exist, so // insert a dummy type to make that header build in gnu++11 mode. R.addDecl(S.getASTContext().getFloat128StubType()); return true; } // If this is a builtin on this (or all) targets, create the decl. if (unsigned BuiltinID = II->getBuiltinID()) { // In C++, we don't have any predefined library functions like // 'malloc'. Instead, we'll just error. if (S.getLangOpts().CPlusPlus && S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S.TUScope, R.isForRedeclaration(), R.getNameLoc())) { R.addDecl(D); return true; } } } } return false; } /// \brief Determine whether we can declare a special member function within /// the class at this point. static bool CanDeclareSpecialMemberFunction(const CXXRecordDecl *Class) { // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; // We can't be in the middle of defining the class. return !Class->isBeingDefined(); } void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (!CanDeclareSpecialMemberFunction(Class)) return; // If the default constructor has not yet been declared, do so now. if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); // If the copy constructor has not yet been declared, do so now. if (Class->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(Class); // If the copy assignment operator has not yet been declared, do so now. if (Class->needsImplicitCopyAssignment()) DeclareImplicitCopyAssignment(Class); if (getLangOpts().CPlusPlus11) { // If the move constructor has not yet been declared, do so now. if (Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); // might not actually do it // If the move assignment operator has not yet been declared, do so now. if (Class->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(Class); // might not actually do it } // If the destructor has not yet been declared, do so now. if (Class->needsImplicitDestructor()) DeclareImplicitDestructor(Class); } /// \brief Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; case DeclarationName::CXXOperatorName: return Name.getCXXOverloadedOperator() == OO_Equal; default: break; } return false; } /// \brief If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, const DeclContext *DC) { if (!DC) return; switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) { CXXRecordDecl *Class = const_cast(Record); if (Record->needsImplicitDefaultConstructor()) S.DeclareImplicitDefaultConstructor(Class); if (Record->needsImplicitCopyConstructor()) S.DeclareImplicitCopyConstructor(Class); if (S.getLangOpts().CPlusPlus11 && Record->needsImplicitMoveConstructor()) S.DeclareImplicitMoveConstructor(Class); } break; case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast(DC)) if (Record->getDefinition() && Record->needsImplicitDestructor() && CanDeclareSpecialMemberFunction(Record)) S.DeclareImplicitDestructor(const_cast(Record)); break; case DeclarationName::CXXOperatorName: if (Name.getCXXOverloadedOperator() != OO_Equal) break; if (const CXXRecordDecl *Record = dyn_cast(DC)) { if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) { CXXRecordDecl *Class = const_cast(Record); if (Record->needsImplicitCopyAssignment()) S.DeclareImplicitCopyAssignment(Class); if (S.getLangOpts().CPlusPlus11 && Record->needsImplicitMoveAssignment()) S.DeclareImplicitMoveAssignment(Class); } } break; default: break; } } // Adds all qualifying matches for a name within a decl context to the // given lookup result. Returns true if any matches were found. static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { bool Found = false; // Lazily declare C++ special member functions. if (S.getLangOpts().CPlusPlus) DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC); // Perform lookup into this declaration context. DeclContext::lookup_const_result DR = DC->lookup(R.getLookupName()); for (DeclContext::lookup_const_iterator I = DR.begin(), E = DR.end(); I != E; ++I) { NamedDecl *D = *I; if ((D = R.getAcceptableDecl(D))) { R.addDecl(D); Found = true; } } if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) return true; if (R.getLookupName().getNameKind() != DeclarationName::CXXConversionFunctionName || R.getLookupName().getCXXNameType()->isDependentType() || !isa(DC)) return Found; // C++ [temp.mem]p6: // A specialization of a conversion function template is not found by // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast(DC); if (!Record->isCompleteDefinition()) return Found; for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(), UEnd = Record->conversion_end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast(*U); if (!ConvTemplate) continue; // When we're performing lookup for the purposes of redeclaration, just // add the conversion function template. When we deduce template // arguments for specializations, we'll end up unifying the return // type of the new declaration with the type of the function template. if (R.isForRedeclaration()) { R.addDecl(ConvTemplate); Found = true; continue; } // C++ [temp.mem]p6: // [...] For each such operator, if argument deduction succeeds // (14.9.2.3), the resulting specialization is used as if found by // name lookup. // // When referencing a conversion function for any purpose other than // a redeclaration (such that we'll be building an expression with the // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getNameLoc()); FunctionDecl *Specialization = nullptr; const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs(); assert(ConvProto && "Nonsensical conversion function template type"); // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); EPI.ExceptionSpec = EST_None; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), None, EPI); // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, nullptr, ExpectedType, Specialization, Info) == Sema::TDK_Success) { R.addDecl(Specialization); Found = true; } } return Found; } // Performs C++ unqualified lookup into the given file context. static bool CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); // Perform direct name lookup into the LookupCtx. bool Found = LookupDirect(S, R, NS); // Perform direct name lookup into the namespaces nominated by the // using directives whose common ancestor is this namespace. UnqualUsingDirectiveSet::const_iterator UI, UEnd; std::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); for (; UI != UEnd; ++UI) if (LookupDirect(S, R, UI->getNominatedNamespace())) Found = true; R.resolveKind(); return Found; } static bool isNamespaceOrTranslationUnitScope(Scope *S) { if (DeclContext *Ctx = S->getEntity()) return Ctx->isFileContext(); return false; } // Find the next outer declaration context from this scope. This // routine actually returns the semantic outer context, which may // differ from the lexical context (encoded directly in the Scope // stack) when we are parsing a member of a class template. In this // case, the second element of the pair will be true, to indicate that // name lookup should continue searching in this semantic context when // it leaves the current template parameter scope. static std::pair findOuterContext(Scope *S) { DeclContext *DC = S->getEntity(); DeclContext *Lexical = nullptr; for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = OuterS->getEntity(); break; } } // C++ [temp.local]p8: // In the definition of a member of a class template that appears // outside of the namespace containing the class template // definition, the name of a template-parameter hides the name of // a member of this namespace. // // Example: // // namespace N { // class C { }; // // template class B { // void f(T); // }; // } // // template void N::B::f(C) { // C b; // C is the template parameter, not N::C // } // // In this example, the lexical context we return is the // TranslationUnit, while the semantic context is the namespace N. if (!Lexical || !DC || !S->getParent() || !S->getParent()->isTemplateParamScope()) return std::make_pair(Lexical, false); // Find the outermost template parameter scope. // For the example, this is the scope for the template parameters of // template. Scope *OutermostTemplateScope = S->getParent(); while (OutermostTemplateScope->getParent() && OutermostTemplateScope->getParent()->isTemplateParamScope()) OutermostTemplateScope = OutermostTemplateScope->getParent(); // Find the namespace context in which the original scope occurs. In // the example, this is namespace N. DeclContext *Semantic = DC; while (!Semantic->isFileContext()) Semantic = Semantic->getParent(); // Find the declaration context just outside of the template // parameter scope. This is the context in which the template is // being lexically declaration (a namespace context). In the // example, this is the global scope. if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && Lexical->Encloses(Semantic)) return std::make_pair(Semantic, true); return std::make_pair(Lexical, false); } namespace { /// An RAII object to specify that we want to find block scope extern /// declarations. struct FindLocalExternScope { FindLocalExternScope(LookupResult &R) : R(R), OldFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_LocalExtern) { R.setFindLocalExtern(R.getIdentifierNamespace() & Decl::IDNS_Ordinary); } void restore() { R.setFindLocalExtern(OldFindLocalExtern); } ~FindLocalExternScope() { restore(); } LookupResult &R; bool OldFindLocalExtern; }; } bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup"); DeclarationName Name = R.getLookupName(); Sema::LookupNameKind NameKind = R.getLookupKind(); // If this is the name of an implicitly-declared special member function, // go through the scope stack to implicitly declare if (isImplicitlyDeclaredMemberFunctionName(Name)) { for (Scope *PreS = S; PreS; PreS = PreS->getParent()) if (DeclContext *DC = PreS->getEntity()) DeclareImplicitMemberFunctionsWithName(*this, Name, DC); } // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. Scope *Initial = S; IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); // First we lookup local scope. // We don't consider using-directives, as per 7.3.4.p1 [namespace.udir] // ...During unqualified name lookup (3.4.1), the names appear as if // they were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. // [Note: in this context, "contains" means "contains directly or // indirectly". // // For example: // namespace A { int i; } // void foo() { // int i; // { // using namespace A; // ++i; // finds local 'i', A::i appears at global scope // } // } // UnqualUsingDirectiveSet UDirs; bool VisitedUsingDirectives = false; bool LeftStartingScope = false; DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = S->getEntity(); // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(*I); ++I) { if (NamedDecl *ND = R.getAcceptableDecl(*I)) { if (NameKind == LookupRedeclarationWithLinkage) { // Determine whether this (or a previous) declaration is // out-of-scope. if (!LeftStartingScope && !Initial->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that // does not have linkage, skip it. If it's a template parameter, // we still find it, so we can diagnose the invalid redeclaration. if (LeftStartingScope && !((*I)->hasLinkage()) && !(*I)->isTemplateParameter()) { R.setShadowed(); continue; } } Found = true; R.addDecl(ND); } } if (Found) { R.resolveKind(); if (S->isClassScope()) if (CXXRecordDecl *Record = dyn_cast_or_null(Ctx)) R.setNamingClass(Record); return true; } if (NameKind == LookupLocalFriendName && !S->isClassScope()) { // C++11 [class.friend]p11: // If a friend declaration appears in a local class and the name // specified is an unqualified name, a prior declaration is // looked up without considering scopes that are outside the // innermost enclosing non-class scope. return false; } if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && S->getParent() && !S->getParent()->isTemplateParamScope()) { // We've just searched the last template parameter scope and // found nothing, so look into the contexts between the // lexical and semantic declaration contexts returned by // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. if (Ctx->isTransparentContext()) continue; // We do not look directly into function or method contexts, // since all of the local variables and parameters of the // function/method are present within the Scope. if (Ctx->isFunctionOrMethod()) { // If we have an Objective-C instance method, look for ivars // in the corresponding interface. if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { if (Method->isInstanceMethod() && Name.getAsIdentifierInfo()) if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( Name.getAsIdentifierInfo(), ClassDeclared)) { if (NamedDecl *ND = R.getAcceptableDecl(Ivar)) { R.addDecl(ND); R.resolveKind(); return true; } } } } continue; } // If this is a file context, we need to perform unqualified name // lookup considering using directives. if (Ctx->isFileContext()) { // If we haven't handled using directives yet, do so now. if (!VisitedUsingDirectives) { // Add using directives from this context up to the top level. for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) { if (UCtx->isTransparentContext()) continue; UDirs.visit(UCtx, UCtx); } // Find the innermost file scope, so we can add using directives // from local scopes. Scope *InnermostFileScope = S; while (InnermostFileScope && !isNamespaceOrTranslationUnitScope(InnermostFileScope)) InnermostFileScope = InnermostFileScope->getParent(); UDirs.visitScopeChain(Initial, InnermostFileScope); UDirs.done(); VisitedUsingDirectives = true; } if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { R.resolveKind(); return true; } continue; } // Perform qualified name lookup into this context. // FIXME: In some cases, we know that every name that could be found by // this qualified name lookup will also be on the identifier chain. For // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; } } } // Stop if we ran out of scopes. // FIXME: This really, really shouldn't be happening. if (!S) return false; // If we are looking for members, no need to look into global/namespace scope. if (NameKind == LookupMemberName) return false; // Collect UsingDirectiveDecls in all scopes, and recursively all // nominated namespaces by those using-directives. // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! if (!VisitedUsingDirectives) { UDirs.visitScopeChain(Initial, S); UDirs.done(); } // If we're not performing redeclaration lookup, do not look for local // extern declarations outside of a function scope. if (!R.isForRedeclaration()) FindLocals.restore(); // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes // that aren't strictly lexical, and therefore we walk through the // context as well as walking through the scopes. for (; S; S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; for (; I != IEnd && S->isDeclScope(*I); ++I) { if (NamedDecl *ND = R.getAcceptableDecl(*I)) { // We found something. Look for anything else in our scope // with this same name and in an acceptable identifier // namespace, so that we can construct an overload set if we // need to. Found = true; R.addDecl(ND); } } if (Found && S->isTemplateParamScope()) { R.resolveKind(); return true; } DeclContext *Ctx = S->getEntity(); if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && S->getParent() && !S->getParent()->isTemplateParamScope()) { // We've just searched the last template parameter scope and // found nothing, so look into the contexts between the // lexical and semantic declaration contexts returned by // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. if (Ctx->isTransparentContext()) continue; // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. if (!(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); // Look into context considering using-directives. if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) Found = true; } if (Found) { R.resolveKind(); return true; } if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } } if (R.isForRedeclaration() && Ctx && !Ctx->isTransparentContext()) return false; } return !R.empty(); } /// \brief Find the declaration that a class temploid member specialization was /// instantiated from, or the member itself if it is an explicit specialization. static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) { return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom(); } /// \brief Find the module in which the given declaration was defined. static Module *getDefiningModule(Decl *Entity) { if (FunctionDecl *FD = dyn_cast(Entity)) { // If this function was instantiated from a template, the defining module is // the module containing the pattern. if (FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (CXXRecordDecl *RD = dyn_cast(Entity)) { if (CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern()) Entity = Pattern; } else if (EnumDecl *ED = dyn_cast(Entity)) { if (MemberSpecializationInfo *MSInfo = ED->getMemberSpecializationInfo()) Entity = getInstantiatedFrom(ED, MSInfo); } else if (VarDecl *VD = dyn_cast(Entity)) { // FIXME: Map from variable template specializations back to the template. if (MemberSpecializationInfo *MSInfo = VD->getMemberSpecializationInfo()) Entity = getInstantiatedFrom(VD, MSInfo); } // Walk up to the containing context. That might also have been instantiated // from a template. DeclContext *Context = Entity->getDeclContext(); if (Context->isFileContext()) return Entity->getOwningModule(); return getDefiningModule(cast(Context)); } llvm::DenseSet &Sema::getLookupModules() { unsigned N = ActiveTemplateInstantiations.size(); for (unsigned I = ActiveTemplateInstantiationLookupModules.size(); I != N; ++I) { Module *M = getDefiningModule(ActiveTemplateInstantiations[I].Entity); if (M && !LookupModulesCache.insert(M).second) M = nullptr; ActiveTemplateInstantiationLookupModules.push_back(M); } return LookupModulesCache; } /// \brief Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current /// lookup context, taking into account the current template instantiation /// stack. During template instantiation, a declaration is visible if it is /// visible from a module containing any entity on the template instantiation /// path (by instantiating a template, you allow it to see the declarations that /// your module can see, including those later on in your module). bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(D->isHidden() && !SemaRef.ActiveTemplateInstantiations.empty() && "should not call this: not in slow case"); Module *DeclModule = D->getOwningModule(); assert(DeclModule && "hidden decl not from a module"); // Find the extra places where we need to look. llvm::DenseSet &LookupModules = SemaRef.getLookupModules(); if (LookupModules.empty()) return false; // If our lookup set contains the decl's module, it's visible. if (LookupModules.count(DeclModule)) return true; // If the declaration isn't exported, it's not visible in any other module. if (D->isModulePrivate()) return false; // Check whether DeclModule is transitively exported to an import of // the lookup set. for (llvm::DenseSet::iterator I = LookupModules.begin(), E = LookupModules.end(); I != E; ++I) if ((*I)->isModuleVisible(DeclModule)) return true; return false; } /// \brief Retrieve the visible declaration corresponding to D, if any. /// /// This routine determines whether the declaration D is visible in the current /// module, with the current imports. If not, it checks whether any /// redeclaration of D is visible, and if so, returns that declaration. /// /// \returns D, or a visible previous declaration of D, whichever is more recent /// and visible. If no declaration of D is visible, returns null. static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); for (auto RD : D->redecls()) { if (auto ND = dyn_cast(RD)) { if (LookupResult::isVisible(SemaRef, ND)) return ND; } } return nullptr; } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { return findAcceptableDecl(getSema(), D); } /// @brief Perform unqualified name lookup starting from a given /// scope. /// /// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is /// used to find names within the current scope. For example, 'x' in /// @code /// int x; /// int f() { /// return x; // unqualified name look finds 'x' in the global scope /// } /// @endcode /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same /// name, and each can be found by certain lookup criteria. For more /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// /// @param S The scope from which unqualified name lookup will /// begin. If the lookup criteria permits, name lookup may also search /// in the parent scopes. /// /// @param [in,out] R Specifies the lookup to perform (e.g., the name to /// look up and the lookup kind), and is updated with the results of lookup /// including zero or more declarations and possibly additional information /// used to diagnose ambiguities. /// /// @returns \c true if lookup succeeded and false otherwise. bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { DeclarationName Name = R.getLookupName(); if (!Name) return false; LookupNameKind NameKind = R.getLookupKind(); if (!getLangOpts().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. if (NameKind == Sema::LookupRedeclarationWithLinkage) { // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || (S->getEntity() && S->getEntity()->isTransparentContext())) S = S->getParent(); } // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); // Scan up the scope chain looking for a decl that matches this // identifier that is in the appropriate namespace. This search // should not take long, as shadowing of names is uncommon, and // deep shadowing is extremely uncommon. bool LeftStartingScope = false; for (IdentifierResolver::iterator I = IdResolver.begin(Name), IEnd = IdResolver.end(); I != IEnd; ++I) if (NamedDecl *D = R.getAcceptableDecl(*I)) { if (NameKind == LookupRedeclarationWithLinkage) { // Determine whether this (or a previous) declaration is // out-of-scope. if (!LeftStartingScope && !S->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that // does not have linkage, skip it. if (LeftStartingScope && !((*I)->hasLinkage())) { R.setShadowed(); continue; } } else if (NameKind == LookupObjCImplicitSelfParam && !isa(*I)) continue; R.addDecl(D); // Check whether there are any other declarations with the same name // and in the same scope. if (I != IEnd) { // Find the scope in which this declaration was declared (if it // actually exists in a Scope). while (S && !S->isDeclScope(D)) S = S->getParent(); // If the scope containing the declaration is the translation unit, // then we'll need to perform our checks based on the matching // DeclContexts rather than matching scopes. if (S && isNamespaceOrTranslationUnitScope(S)) S = nullptr; // Compute the DeclContext, if we need it. DeclContext *DC = nullptr; if (!S) DC = (*I)->getDeclContext()->getRedeclContext(); IdentifierResolver::iterator LastI = I; for (++LastI; LastI != IEnd; ++LastI) { if (S) { // Match based on scope. if (!S->isDeclScope(*LastI)) break; } else { // Match based on DeclContext. DeclContext *LastDC = (*LastI)->getDeclContext()->getRedeclContext(); if (!LastDC->Equals(DC)) break; } // If the declaration is in the right namespace and visible, add it. if (NamedDecl *LastD = R.getAcceptableDecl(*LastI)) R.addDecl(LastD); } R.resolveKind(); } return true; } } else { // Perform C++ unqualified name lookup. if (CppLookupName(R, S)) return true; } // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. if (AllowBuiltinCreation && LookupBuiltin(*this, R)) return true; // If we didn't find a use of this identifier, the ExternalSource // may be able to handle the situation. // Note: some lookup failures are expected! // See e.g. R.isForRedeclaration(). return (ExternalSource && ExternalSource->LookupUnqualified(R, S)); } /// @brief Perform qualified name lookup in the namespaces nominated by /// using directives by the given context. /// /// C++98 [namespace.qual]p2: /// Given X::m (where X is a user-declared namespace), or given \::m /// (where X is the global namespace), let S be the set of all /// declarations of m in X and in the transitive closure of all /// namespaces nominated by using-directives in X and its used /// namespaces, except that using-directives are ignored in any /// namespace, including X, directly containing one or more /// declarations of m. No namespace is searched more than once in /// the lookup of a name. If S is the empty set, the program is /// ill-formed. Otherwise, if S has exactly one member, or if the /// context of the reference is a using-declaration /// (namespace.udecl), S is the required set of declarations of /// m. Otherwise if the use of m is not one that allows a unique /// declaration to be chosen from S, the program is ill-formed. /// /// C++98 [namespace.qual]p5: /// During the lookup of a qualified namespace member name, if the /// lookup finds more than one declaration of the member, and if one /// declaration introduces a class name or enumeration name and the /// other declarations either introduce the same object, the same /// enumerator or a set of functions, the non-type name hides the /// class or enumeration name if and only if the declarations are /// from the same namespace; otherwise (the declarations are from /// different namespaces), the program is ill-formed. static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); DeclContext::udir_range UsingDirectives = StartDC->using_directives(); if (UsingDirectives.begin() == UsingDirectives.end()) return false; // We have at least added all these contexts to the queue. llvm::SmallPtrSet Visited; Visited.insert(StartDC); // We have not yet looked into these namespaces, much less added // their "using-children" to the queue. SmallVector Queue; // We have already looked into the initial namespace; seed the queue // with its using-children. for (auto *I : UsingDirectives) { NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); if (Visited.insert(ND).second) Queue.push_back(ND); } // The easiest way to implement the restriction in [namespace.qual]p5 // is to check whether any of the individual results found a tag // and, if so, to declare an ambiguity if the final result is not // a tag. bool FoundTag = false; bool FoundNonTag = false; LookupResult LocalR(LookupResult::Temporary, R); bool Found = false; while (!Queue.empty()) { NamespaceDecl *ND = Queue.pop_back_val(); // We go through some convolutions here to avoid copying results // between LookupResults. bool UseLocal = !R.empty(); LookupResult &DirectR = UseLocal ? LocalR : R; bool FoundDirect = LookupDirect(S, DirectR, ND); if (FoundDirect) { // First do any local hiding. DirectR.resolveKind(); // If the local result is a tag, remember that. if (DirectR.isSingleTagDecl()) FoundTag = true; else FoundNonTag = true; // Append the local results to the total results if necessary. if (UseLocal) { R.addAllDecls(LocalR); LocalR.clear(); } } // If we find names in this namespace, ignore its using directives. if (FoundDirect) { Found = true; continue; } for (auto I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); if (Visited.insert(Nom).second) Queue.push_back(Nom); } } if (Found) { if (FoundTag && FoundNonTag) R.setAmbiguousQualifiedTagHiding(); else R.resolveKind(); } return Found; } /// \brief Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); Path.Decls = BaseRecord->lookup(N); return !Path.Decls.empty(); } /// \brief Determine whether the given set of member declarations contains only /// static members, nested types, and enumerators. template static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { Decl *D = (*First)->getUnderlyingDecl(); if (isa(D) || isa(D) || isa(D)) return true; if (isa(D)) { // Determine whether all of the methods are static. bool AllMethodsAreStatic = true; for(; First != Last; ++First) { D = (*First)->getUnderlyingDecl(); if (!isa(D)) { assert(isa(D) && "Non-function must be a tag decl"); break; } if (!cast(D)->isStatic()) { AllMethodsAreStatic = false; break; } } if (AllMethodsAreStatic) return true; } return false; } /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find /// names when the context of those names is explicit specified, e.g., /// "std::vector" or "x->member", or as part of unqualified name lookup. /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same /// name, and each can be found by certain lookup criteria. For more /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param LookupCtx The context in which qualified name lookup will /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// /// \param InUnqualifiedLookup true if this is qualified name lookup that /// occurs as part of unqualified name lookup. /// /// \returns true if lookup succeeded, false if it failed. bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); if (!R.getLookupName()) return false; // Make sure that the declaration context is complete. assert((!isa(LookupCtx) || LookupCtx->isDependentContext() || cast(LookupCtx)->isCompleteDefinition() || cast(LookupCtx)->isBeingDefined()) && "Declaration context must already be complete!"); // Perform qualified name lookup into the LookupCtx. if (LookupDirect(*this, R, LookupCtx)) { R.resolveKind(); if (isa(LookupCtx)) R.setNamingClass(cast(LookupCtx)); return true; } // Don't descend into implied contexts for redeclarations. // C++98 [namespace.qual]p6: // In a declaration for a namespace member in which the // declarator-id is a qualified-id, given that the qualified-id // for the namespace member has the form // nested-name-specifier unqualified-id // the unqualified-id shall name a member of the namespace // designated by the nested-name-specifier. // See also [class.mfct]p5 and [class.static.data]p2. if (R.isForRedeclaration()) return false; // If this is a namespace, look it up in the implied namespaces. if (LookupCtx->isFileContext()) return LookupQualifiedNameInUsingDirectives(*this, R, LookupCtx); // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. CXXRecordDecl *LookupRec = dyn_cast(LookupCtx); if (!LookupRec || !LookupRec->getDefinition()) return false; // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any // dependent base classes, then we either have to delay lookup until // template instantiation time (at which point all bases will be available) // or we have to fail. if (!InUnqualifiedLookup && LookupRec->isDependentContext() && LookupRec->hasAnyDependentBases()) { R.setNotFoundInCurrentInstantiation(); return false; } // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(LookupRec); // Look for this member in our base classes CXXRecordDecl::BaseMatchesCallback *BaseCallback = nullptr; switch (R.getLookupKind()) { case LookupObjCImplicitSelfParam: case LookupOrdinaryName: case LookupMemberName: case LookupRedeclarationWithLinkage: case LookupLocalFriendName: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; case LookupAnyName: BaseCallback = &LookupAnyMember; break; case LookupUsingDeclName: // This lookup is for redeclarations only. case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: case LookupLabel: // These lookups will never find a member in a C++ class (or base class). return false; case LookupNestedNameSpecifierName: BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; break; } if (!LookupRec->lookupInBases(BaseCallback, R.getLookupName().getAsOpaquePtr(), Paths)) return false; R.setNamingClass(LookupRec); // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from // sub-objects of the same type, or the set has a nonstatic member // and includes members from distinct sub-objects, there is an // ambiguity and the program is ill-formed. Otherwise that set is // the result of the lookup. QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); // Pick the best (i.e. most permissive i.e. numerically lowest) access // across all paths. SubobjectAccess = std::min(SubobjectAccess, Path->Access); // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; continue; } if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of // different types. If the declaration sets aren't the same, this // lookup is ambiguous. if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) { CXXBasePaths::paths_iterator FirstPath = Paths.begin(); DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); DeclContext::lookup_iterator CurrentD = Path->Decls.begin(); while (FirstD != FirstPath->Decls.end() && CurrentD != Path->Decls.end()) { if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) break; ++FirstD; ++CurrentD; } if (FirstD == FirstPath->Decls.end() && CurrentD == Path->Decls.end()) continue; } R.setAmbiguousBaseSubobjectTypes(Paths); return true; } if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. // C++ [class.member.lookup]p5: // A static member, a nested type or an enumerator defined in // a base class T can unambiguously be found even if an object // has more than one base class subobject of type T. if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) continue; // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); return true; } } // Lookup in a base class succeeded; return these results. for (auto *D : Paths.front().Decls) { AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, D->getAccess()); R.addDecl(D, AS); } R.resolveKind(); return true; } /// \brief Performs qualified name lookup or special type of lookup for /// "__super::" scope specifier. /// /// This routine is a convenience overload meant to be called from contexts /// that need to perform a qualified name lookup with an optional C++ scope /// specifier that might require special kind of lookup. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param LookupCtx The context in which qualified name lookup will /// search. /// /// \param SS An optional C++ scope-specifier. /// /// \returns true if lookup succeeded, false if it failed. bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS) { auto *NNS = SS.getScopeRep(); if (NNS && NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); else return LookupQualifiedName(R, LookupCtx); } /// @brief Performs name lookup for a name that was parsed in the /// source code, and may contain a C++ scope specifier. /// /// This routine is a convenience routine meant to be called from /// contexts that receive a name and an optional C++ scope specifier /// (e.g., "N::M::x"). It will then perform either qualified or /// unqualified name lookup (with LookupQualifiedName or LookupName, /// respectively) on the given name and return those results. It will /// perform a special type of lookup for "__super::" scope specifier. /// /// @param S The scope from which unqualified name lookup will /// begin. /// /// @param SS An optional C++ scope-specifier, e.g., "::N::M". /// /// @param EnteringContext Indicates whether we are going to enter the /// context of the scope-specifier SS (if present). /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation, bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for // anything. return false; } if (SS && SS->isSet()) { NestedNameSpecifier *NNS = SS->getScopeRep(); if (NNS->getKind() == NestedNameSpecifier::Super) return LookupInSuper(R, NNS->getAsRecordDecl()); if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; R.setContextRange(SS->getRange()); return LookupQualifiedName(R, DC); } // We could not resolve the scope specified to a specific declaration // context, which means that SS refers to an unknown specialization. // Name lookup can't find anything in this case. R.setNotFoundInCurrentInstantiation(); R.setContextRange(SS->getRange()); return false; } // Perform unqualified name lookup starting in the given scope. return LookupName(R, S, AllowBuiltinCreation); } /// \brief Perform qualified name lookup into all base classes of the given /// class. /// /// \param R captures both the lookup criteria and any lookup results found. /// /// \param Class The context in which qualified name lookup will /// search. Name lookup will search in all base classes merging the results. /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { for (const auto &BaseSpec : Class->bases()) { CXXRecordDecl *RD = cast( BaseSpec.getType()->castAs()->getDecl()); LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); Result.setBaseObjectType(Context.getRecordType(Class)); LookupQualifiedName(Result, RD); for (auto *Decl : Result) R.addDecl(Decl); } R.resolveKind(); return !R.empty(); } /// \brief Produce a diagnostic describing the ambiguity that resulted /// from name lookup. /// /// \param Result The result of the ambiguous lookup to be diagnosed. void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); DeclarationName Name = Result.getLookupName(); SourceLocation NameLoc = Result.getNameLoc(); SourceRange LookupRange = Result.getContextRange(); switch (Result.getAmbiguityKind()) { case LookupResult::AmbiguousBaseSubobjects: { CXXBasePaths *Paths = Result.getBasePaths(); QualType SubobjectType = Paths->front().back().Base->getType(); Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) << LookupRange; DeclContext::lookup_iterator Found = Paths->front().Decls.begin(); while (isa(*Found) && cast(*Found)->isStatic()) ++Found; Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); break; } case LookupResult::AmbiguousBaseSubobjectTypes: { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) << Name << LookupRange; CXXBasePaths *Paths = Result.getBasePaths(); std::set DeclsPrinted; for (CXXBasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); Path != PathEnd; ++Path) { Decl *D = Path->Decls.front(); if (DeclsPrinted.insert(D).second) Diag(D->getLocation(), diag::note_ambiguous_member_found); } break; } case LookupResult::AmbiguousTagHiding: { Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange; llvm::SmallPtrSet TagDecls; for (auto *D : Result) if (TagDecl *TD = dyn_cast(D)) { TagDecls.insert(TD); Diag(TD->getLocation(), diag::note_hidden_tag); } for (auto *D : Result) if (!isa(D)) Diag(D->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. LookupResult::Filter F = Result.makeFilter(); while (F.hasNext()) { if (TagDecls.count(F.next())) F.erase(); } F.done(); break; } case LookupResult::AmbiguousReference: { Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; for (auto *D : Result) Diag(D->getLocation(), diag::note_ambiguous_candidate) << D; break; } } } namespace { struct AssociatedLookup { AssociatedLookup(Sema &S, SourceLocation InstantiationLoc, Sema::AssociatedNamespaceSet &Namespaces, Sema::AssociatedClassSet &Classes) : S(S), Namespaces(Namespaces), Classes(Classes), InstantiationLoc(InstantiationLoc) { } Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; SourceLocation InstantiationLoc; }; } static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType T); static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, DeclContext *Ctx) { // Add the associated namespace for this class. // We don't use DeclContext::getEnclosingNamespaceContext() as this may // be a locally scoped record. // We skip out of inline namespaces. The innermost non-inline namespace // contains all names of all its nested inline namespaces anyway, so we can // replace the entire inline namespace tree with its root. while (Ctx->isRecord() || Ctx->isTransparentContext() || Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); if (Ctx->isFileContext()) Namespaces.insert(Ctx->getPrimaryContext()); } // \brief Add the associated classes and namespaces for argument-dependent // lookup that involves a template argument (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, const TemplateArgument &Arg) { // C++ [basic.lookup.koenig]p2, last bullet: // -- [...] ; switch (Arg.getKind()) { case TemplateArgument::Null: break; case TemplateArgument::Type: // [...] the namespaces and classes associated with the types of the // template arguments provided for template type parameters (excluding // template template parameters) addAssociatedClassesAndNamespaces(Result, Arg.getAsType()); break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as // template template arguments are defined. TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (ClassTemplateDecl *ClassTemplate = dyn_cast(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); } break; } case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: case TemplateArgument::NullPtr: // [Note: non-type template arguments do not contribute to the set of // associated namespaces. ] break; case TemplateArgument::Pack: for (const auto &P : Arg.pack_elements()) addAssociatedClassesAndNamespaces(Result, P); break; } } // \brief Add the associated classes and namespaces for // argument-dependent lookup with an argument of class type // (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, CXXRecordDecl *Class) { // Just silently ignore anything whose name is __va_list_tag. if (Class->getDeclName() == Result.S.VAListTagName) return; // C++ [basic.lookup.koenig]p2: // [...] // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in // which its associated classes are defined. // Add the class of which it is a member, if any. DeclContext *Ctx = Class->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); // Add the class itself. If we've already seen this class, we don't // need to visit base classes. // // FIXME: That's not correct, we may have added this class only because it // was the enclosing class of another class, and in that case we won't have // added its base classes yet. if (!Result.Classes.insert(Class).second) return; // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member // templates, the member template's class; the namespaces and classes // associated with the types of the template arguments provided for // template type parameters (excluding template template parameters); the // namespaces in which any template template arguments are defined; and // the classes in which any member templates used as template template // arguments are defined. [Note: non-type template arguments do not // contribute to the set of associated namespaces. ] if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Class)) { DeclContext *Ctx = Spec->getSpecializedTemplate()->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) addAssociatedClassesAndNamespaces(Result, TemplateArgs[I]); } // Only recurse into base classes for complete types. if (!Class->hasDefinition()) return; // Add direct and indirect base classes along with their associated // namespaces. SmallVector Bases; Bases.push_back(Class); while (!Bases.empty()) { // Pop this class off the stack. Class = Bases.pop_back_val(); // Visit the base classes. for (const auto &Base : Class->bases()) { const RecordType *BaseType = Base.getType()->getAs(); // In dependent contexts, we do ADL twice, and the first time around, // the base type might be a dependent TemplateSpecializationType, or a // TemplateTypeParmType. If that happens, simply ignore it. // FIXME: If we want to support export, we probably need to add the // namespace of the template in a TemplateSpecializationType, or even // the classes and namespaces of known non-dependent arguments. if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast(BaseType->getDecl()); if (Result.Classes.insert(BaseDecl).second) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); // Make sure we visit the bases of this base class. if (BaseDecl->bases_begin() != BaseDecl->bases_end()) Bases.push_back(BaseDecl); } } } } // \brief Add the associated classes and namespaces for // argument-dependent lookup with an argument of type T // (C++ [basic.lookup.koenig]p2). static void addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // C++ [basic.lookup.koenig]p2: // // For each argument type T in the function call, there is a set // of zero or more associated namespaces and a set of zero or more // associated classes to be considered. The sets of namespaces and // classes is determined entirely by the types of the function // arguments (and the namespace of any template template // argument). Typedef names and using-declarations used to specify // the types do not contribute to this set. The sets of namespaces // and classes are determined in the following way: SmallVector Queue; const Type *T = Ty->getCanonicalTypeInternal().getTypePtr(); while (true) { switch (T->getTypeClass()) { #define TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" // T is canonical. We can also ignore dependent types because // we don't need to do ADL at the definition point, but if we // wanted to implement template export (or if we find some other // use for associated classes and namespaces...) this would be // wrong. break; // -- If T is a pointer to U or an array of U, its associated // namespaces and classes are those associated with U. case Type::Pointer: T = cast(T)->getPointeeType().getTypePtr(); continue; case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: T = cast(T)->getElementType().getTypePtr(); continue; // -- If T is a fundamental type, its associated sets of // namespaces and classes are both empty. case Type::Builtin: break; // -- If T is a class type (including unions), its associated // classes are: the class itself; the class of which it is a // member, if any; and its direct and indirect base // classes. Its associated namespaces are the namespaces in // which its associated classes are defined. case Type::Record: { Result.S.RequireCompleteType(Result.InstantiationLoc, QualType(T, 0), /*no diagnostic*/ 0); CXXRecordDecl *Class = cast(cast(T)->getDecl()); addAssociatedClassesAndNamespaces(Result, Class); break; } // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast(T)->getDecl(); DeclContext *Ctx = Enum->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast(Ctx)) Result.Classes.insert(EnclosingClass); // Add the associated namespace for this class. CollectEnclosingNamespace(Result.Namespaces, Ctx); break; } // -- If T is a function type, its associated namespaces and // classes are those associated with the function parameter // types and those associated with the return type. case Type::FunctionProto: { const FunctionProtoType *Proto = cast(T); for (const auto &Arg : Proto->param_types()) Queue.push_back(Arg.getTypePtr()); // fallthrough } case Type::FunctionNoProto: { const FunctionType *FnType = cast(T); T = FnType->getReturnType().getTypePtr(); continue; } // -- If T is a pointer to a member function of a class X, its // associated namespaces and classes are those associated // with the function parameter types and return type, // together with those associated with X. // // -- If T is a pointer to a data member of class X, its // associated namespaces and classes are those associated // with the member type together with those associated with // X. case Type::MemberPointer: { const MemberPointerType *MemberPtr = cast(T); // Queue up the class type into which this points. Queue.push_back(MemberPtr->getClass()); // And directly continue with the pointee type. T = MemberPtr->getPointeeType().getTypePtr(); continue; } // As an extension, treat this like a normal pointer. case Type::BlockPointer: T = cast(T)->getPointeeType().getTypePtr(); continue; // References aren't covered by the standard, but that's such an // obvious defect that we cover them anyway. case Type::LValueReference: case Type::RValueReference: T = cast(T)->getPointeeType().getTypePtr(); continue; // These are fundamental types. case Type::Vector: case Type::ExtVector: case Type::Complex: break; // Non-deduced auto types only get here for error cases. case Type::Auto: break; // If T is an Objective-C object or interface type, or a pointer to an // object or interface type, the associated namespace is the global // namespace. case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; // Atomic types are just wrappers; use the associations of the // contained type. case Type::Atomic: T = cast(T)->getValueType().getTypePtr(); continue; } if (Queue.empty()) break; T = Queue.pop_back_val(); } } /// \brief Find the associated classes and namespaces for /// argument-dependent lookup for a call with the given set of /// arguments. /// /// This routine computes the sets of associated classes and associated /// namespaces searched by argument-dependent lookup /// (C++ [basic.lookup.argdep]) for a given set of arguments. void Sema::FindAssociatedClassesAndNamespaces( SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses) { AssociatedNamespaces.clear(); AssociatedClasses.clear(); AssociatedLookup Result(*this, InstantiationLoc, AssociatedNamespaces, AssociatedClasses); // C++ [basic.lookup.koenig]p2: // For each argument type T in the function call, there is a set // of zero or more associated namespaces and a set of zero or more // associated classes to be considered. The sets of namespaces and // classes is determined entirely by the types of the function // arguments (and the namespace of any template template // argument). for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { Expr *Arg = Args[ArgIdx]; if (Arg->getType() != Context.OverloadTy) { addAssociatedClassesAndNamespaces(Result, Arg->getType()); continue; } // [...] In addition, if the argument is the name or address of a // set of overloaded functions and/or function templates, its // associated classes and namespaces are the union of those // associated with each of the members of the set: the namespace // in which the function or function template is defined and the // classes and namespaces associated with its (non-dependent) // parameter types and return type. Arg = Arg->IgnoreParens(); if (UnaryOperator *unaryOp = dyn_cast(Arg)) if (unaryOp->getOpcode() == UO_AddrOf) Arg = unaryOp->getSubExpr(); UnresolvedLookupExpr *ULE = dyn_cast(Arg); if (!ULE) continue; for (const auto *D : ULE->decls()) { // Look through any using declarations to find the underlying function. const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction(); // Add the classes and namespaces associated with the parameter // types and return type of this function. addAssociatedClassesAndNamespaces(Result, FDecl->getType()); } } } NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl) { LookupResult R(*this, Name, Loc, NameKind, Redecl); LookupName(R, S); return R.getAsSingle(); } /// \brief Find the protocol with the given name, if any. ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl) { Decl *D = LookupSingleName(TUScope, II, IdLoc, LookupObjCProtocolName, Redecl); return cast_or_null(D); } void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions) { // C++ [over.match.oper]p3: // -- The set of non-member candidates is the result of the // unqualified lookup of operator@ in the context of the // expression according to the usual rules for name lookup in // unqualified function calls (3.4.2) except that all member // functions are ignored. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName); LookupName(Operators, S); assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); Functions.append(Operators.begin(), Operators.end()); } Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis) { assert(CanDeclareSpecialMemberFunction(RD) && "doing special member lookup into record that isn't fully complete"); RD = RD->getDefinition(); if (RValueThis || ConstThis || VolatileThis) assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && "constructors and destructors always have unqualified lvalue this"); if (ConstArg || VolatileArg) assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && "parameter-less special members can't have qualified arguments"); llvm::FoldingSetNodeID ID; ID.AddPointer(RD); ID.AddInteger(SM); ID.AddInteger(ConstArg); ID.AddInteger(VolatileArg); ID.AddInteger(RValueThis); ID.AddInteger(ConstThis); ID.AddInteger(VolatileThis); void *InsertPoint; SpecialMemberOverloadResult *Result = SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint); // This was already cached if (Result) return Result; Result = BumpAlloc.Allocate(); Result = new (Result) SpecialMemberOverloadResult(ID); SpecialMemberCache.InsertNode(Result, InsertPoint); if (SM == CXXDestructor) { if (RD->needsImplicitDestructor()) DeclareImplicitDestructor(RD); CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); Result->setKind(DD->isDeleted() ? SpecialMemberOverloadResult::NoMemberOrDeleted : SpecialMemberOverloadResult::Success); return Result; } // Prepare for overload resolution. Here we construct a synthetic argument // if necessary and make sure that implicit functions are declared. CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD)); DeclarationName Name; Expr *Arg = nullptr; unsigned NumArgs; QualType ArgType = CanTy; ExprValueKind VK = VK_LValue; if (SM == CXXDefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; if (RD->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(RD); } else { if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); if (RD->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(RD); if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(RD); } else { Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); if (RD->needsImplicitCopyAssignment()) DeclareImplicitCopyAssignment(RD); if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) DeclareImplicitMoveAssignment(RD); } if (ConstArg) ArgType.addConst(); if (VolatileArg) ArgType.addVolatile(); // This isn't /really/ specified by the standard, but it's implied // we should be working from an RValue in the case of move to ensure // that we prefer to bind to rvalue references, and an LValue in the // case of copy to ensure we don't bind to rvalue references. // Possibly an XValue is actually correct in the case of move, but // there is no semantic difference for class types in this restricted // case. if (SM == CXXCopyConstructor || SM == CXXCopyAssignment) VK = VK_LValue; else VK = VK_RValue; } OpaqueValueExpr FakeArg(SourceLocation(), ArgType, VK); if (SM != CXXDefaultConstructor) { NumArgs = 1; Arg = &FakeArg; } // Create the object argument QualType ThisTy = CanTy; if (ConstThis) ThisTy.addConst(); if (VolatileThis) ThisTy.addVolatile(); Expr::Classification Classification = OpaqueValueExpr(SourceLocation(), ThisTy, RValueThis ? VK_RValue : VK_LValue).Classify(Context); // Now we perform lookup on the name we computed earlier and do overload // resolution. Lookup is only performed directly into the class since there // will always be a (possibly implicit) declaration to shadow any others. OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal); DeclContext::lookup_result R = RD->lookup(Name); - assert(!R.empty() && - "lookup for a constructor or assignment operator was empty"); + + if (R.empty()) { + // We might have no default constructor because we have a lambda's closure + // type, rather than because there's some other declared constructor. + // Every class has a copy/move constructor, copy/move assignment, and + // destructor. + assert(SM == CXXDefaultConstructor && + "lookup for a constructor or assignment operator was empty"); + Result->setMethod(nullptr); + Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); + return Result; + } // Copy the candidates as our processing of them may load new declarations // from an external source and invalidate lookup_result. SmallVector Candidates(R.begin(), R.end()); for (auto *Cand : Candidates) { if (Cand->isInvalidDecl()) continue; if (UsingShadowDecl *U = dyn_cast(Cand)) { // FIXME: [namespace.udecl]p15 says that we should only consider a // using declaration here if it does not match a declaration in the // derived class. We do not implement this correctly in other cases // either. Cand = U->getTargetDecl(); if (Cand->isInvalidDecl()) continue; } if (CXXMethodDecl *M = dyn_cast(Cand)) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else if (FunctionTemplateDecl *Tmpl = dyn_cast(Cand)) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), RD, nullptr, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else { assert(isa(Cand) && "illegal Kind of operator = Decl"); } } OverloadCandidateSet::iterator Best; switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { case OR_Success: Result->setMethod(cast(Best->Function)); Result->setKind(SpecialMemberOverloadResult::Success); break; case OR_Deleted: Result->setMethod(cast(Best->Function)); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; case OR_Ambiguous: Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::Ambiguous); break; case OR_No_Viable_Function: Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; } return Result; } /// \brief Look up the default constructor for the given class. CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, false, false); return cast_or_null(Result->getMethod()); } /// \brief Look up the copying constructor for the given class. CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy ctor arg"); SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result->getMethod()); } /// \brief Look up the moving constructor for the given class. CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals) { SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result->getMethod()); } /// \brief Look up the constructors for the given class. DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { // If the implicit constructors have not yet been declared, do so now. if (CanDeclareSpecialMemberFunction(Class)) { if (Class->needsImplicitDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); if (Class->needsImplicitCopyConstructor()) DeclareImplicitCopyConstructor(Class); if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor()) DeclareImplicitMoveConstructor(Class); } CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name); } /// \brief Look up the copying assignment operator for the given class. CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment arg"); assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, ThisQuals & Qualifiers::Volatile); return Result->getMethod(); } /// \brief Look up the moving assignment operator for the given class. CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals) { assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); SpecialMemberOverloadResult *Result = LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const, Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, ThisQuals & Qualifiers::Volatile); return Result->getMethod(); } /// \brief Look for the destructor of the given class. /// /// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { return cast(LookupSpecialMember(Class, CXXDestructor, false, false, false, false, false)->getMethod()); } /// LookupLiteralOperator - Determine which literal operator should be used for /// a user-defined literal, per C++11 [lex.ext]. /// /// Normal overload resolution is not used to select which literal operator to /// call for a user-defined literal. Look up the provided literal operator name, /// and filter the results to the appropriate set for the given argument types. Sema::LiteralOperatorLookupResult Sema::LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate) { LookupName(R, S); assert(R.getResultKind() != LookupResult::Ambiguous && "literal operator lookup can't be ambiguous"); // Filter the lookup results appropriately. LookupResult::Filter F = R.makeFilter(); bool FoundRaw = false; bool FoundTemplate = false; bool FoundStringTemplate = false; bool FoundExactMatch = false; while (F.hasNext()) { Decl *D = F.next(); if (UsingShadowDecl *USD = dyn_cast(D)) D = USD->getTargetDecl(); // If the declaration we found is invalid, skip it. if (D->isInvalidDecl()) { F.erase(); continue; } bool IsRaw = false; bool IsTemplate = false; bool IsStringTemplate = false; bool IsExactMatch = false; if (FunctionDecl *FD = dyn_cast(D)) { if (FD->getNumParams() == 1 && FD->getParamDecl(0)->getType()->getAs()) IsRaw = true; else if (FD->getNumParams() == ArgTys.size()) { IsExactMatch = true; for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) { QualType ParamTy = FD->getParamDecl(ArgIdx)->getType(); if (!Context.hasSameUnqualifiedType(ArgTys[ArgIdx], ParamTy)) { IsExactMatch = false; break; } } } } if (FunctionTemplateDecl *FD = dyn_cast(D)) { TemplateParameterList *Params = FD->getTemplateParameters(); if (Params->size() == 1) IsTemplate = true; else IsStringTemplate = true; } if (IsExactMatch) { FoundExactMatch = true; AllowRaw = false; AllowTemplate = false; AllowStringTemplate = false; if (FoundRaw || FoundTemplate || FoundStringTemplate) { // Go through again and remove the raw and template decls we've // already found. F.restart(); FoundRaw = FoundTemplate = FoundStringTemplate = false; } } else if (AllowRaw && IsRaw) { FoundRaw = true; } else if (AllowTemplate && IsTemplate) { FoundTemplate = true; } else if (AllowStringTemplate && IsStringTemplate) { FoundStringTemplate = true; } else { F.erase(); } } F.done(); // C++11 [lex.ext]p3, p4: If S contains a literal operator with a matching // parameter type, that is used in preference to a raw literal operator // or literal operator template. if (FoundExactMatch) return LOLR_Cooked; // C++11 [lex.ext]p3, p4: S shall contain a raw literal operator or a literal // operator template, but not both. if (FoundRaw && FoundTemplate) { Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) NoteOverloadCandidate((*I)->getUnderlyingDecl()->getAsFunction()); return LOLR_Error; } if (FoundRaw) return LOLR_Raw; if (FoundTemplate) return LOLR_Template; if (FoundStringTemplate) return LOLR_StringTemplate; // Didn't find anything we could use. Diag(R.getNameLoc(), diag::err_ovl_no_viable_literal_operator) << R.getLookupName() << (int)ArgTys.size() << ArgTys[0] << (ArgTys.size() == 2 ? ArgTys[1] : QualType()) << AllowRaw << (AllowTemplate || AllowStringTemplate); return LOLR_Error; } void ADLResult::insert(NamedDecl *New) { NamedDecl *&Old = Decls[cast(New->getCanonicalDecl())]; // If we haven't yet seen a decl for this key, or the last decl // was exactly this one, we're done. if (Old == nullptr || Old == New) { Old = New; return; } // Otherwise, decide which is a more recent redeclaration. FunctionDecl *OldFD = Old->getAsFunction(); FunctionDecl *NewFD = New->getAsFunction(); FunctionDecl *Cursor = NewFD; while (true) { Cursor = Cursor->getPreviousDecl(); // If we got to the end without finding OldFD, OldFD is the newer // declaration; leave things as they are. if (!Cursor) return; // If we do find OldFD, then NewFD is newer. if (Cursor == OldFD) break; // Otherwise, keep looking. } Old = New; } void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Result) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; AssociatedClassSet AssociatedClasses; FindAssociatedClassesAndNamespaces(Loc, Args, AssociatedNamespaces, AssociatedClasses); // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent // lookup (defined as follows). If X contains [...] then Y is // empty. Otherwise Y is the set of declarations found in the // namespaces associated with the argument types as described // below. The set of declarations found by the lookup of the name // is the union of X and Y. // // Here, we compute Y and add its members to the overloaded // candidate set. for (auto *NS : AssociatedNamespaces) { // When considering an associated namespace, the lookup is the // same as the lookup performed when the associated namespace is // used as a qualifier (3.4.3.2) except that: // // -- Any using-directives in the associated namespace are // ignored. // // -- Any namespace-scope friend functions declared in // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). DeclContext::lookup_result R = NS->lookup(Name); for (auto *D : R) { // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) { // If it's neither ordinarily visible nor a friend, we can't find it. if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0) continue; bool DeclaredInAssociatedClass = false; for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) { DeclContext *LexDC = DI->getLexicalDeclContext(); if (isa(LexDC) && AssociatedClasses.count(cast(LexDC))) { DeclaredInAssociatedClass = true; break; } } if (!DeclaredInAssociatedClass) continue; } if (isa(D)) D = cast(D)->getTargetDecl(); if (!isa(D) && !isa(D)) continue; Result.insert(D); } } } //---------------------------------------------------------------------------- // Search for all visible declarations. //---------------------------------------------------------------------------- VisibleDeclConsumer::~VisibleDeclConsumer() { } bool VisibleDeclConsumer::includeHiddenDecls() const { return false; } namespace { class ShadowContextRAII; class VisibleDeclsRecord { public: /// \brief An entry in the shadow map, which is optimized to store a /// single declaration (the common case) but can also store a list /// of declarations. typedef llvm::TinyPtrVector ShadowMapEntry; private: /// \brief A mapping from declaration names to the declarations that have /// this name within a particular scope. typedef llvm::DenseMap ShadowMap; /// \brief A list of shadow maps, which is used to model name hiding. std::list ShadowMaps; /// \brief The declaration contexts we have already visited. llvm::SmallPtrSet VisitedContexts; friend class ShadowContextRAII; public: /// \brief Determine whether we have already visited this context /// (and, if not, note that we are going to visit that context now). bool visitedContext(DeclContext *Ctx) { return !VisitedContexts.insert(Ctx).second; } bool alreadyVisitedContext(DeclContext *Ctx) { return VisitedContexts.count(Ctx); } /// \brief Determine whether the given declaration is hidden in the /// current scope. /// /// \returns the declaration that hides the given declaration, or /// NULL if no such declaration exists. NamedDecl *checkHidden(NamedDecl *ND); /// \brief Add a declaration to the current shadow map. void add(NamedDecl *ND) { ShadowMaps.back()[ND->getDeclName()].push_back(ND); } }; /// \brief RAII object that records when we've entered a shadow context. class ShadowContextRAII { VisibleDeclsRecord &Visible; typedef VisibleDeclsRecord::ShadowMap ShadowMap; public: ShadowContextRAII(VisibleDeclsRecord &Visible) : Visible(Visible) { Visible.ShadowMaps.push_back(ShadowMap()); } ~ShadowContextRAII() { Visible.ShadowMaps.pop_back(); } }; } // end anonymous namespace NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); unsigned IDNS = ND->getIdentifierNamespace(); std::list::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list::reverse_iterator SMEnd = ShadowMaps.rend(); SM != SMEnd; ++SM) { ShadowMap::iterator Pos = SM->find(ND->getDeclName()); if (Pos == SM->end()) continue; for (auto *D : Pos->second) { // A tag declaration does not hide a non-tag declaration. if (D->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. if (((D->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && D->getIdentifierNamespace() != IDNS) continue; // Functions and function templates in the same scope overload // rather than hide. FIXME: Look for hiding based on function // signatures! if (D->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && ND->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; // We've found a declaration that hides this one. return D; } } return nullptr; } static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { if (!Ctx) return; // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; if (CXXRecordDecl *Class = dyn_cast(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. for (const auto &R : Ctx->lookups()) { for (auto *I : R) { if (NamedDecl *ND = dyn_cast(I)) { if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); } } } } // Traverse using directives for qualified name lookup. if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); for (auto I : Ctx->using_directives()) { LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast(Ctx)) { if (!Record->hasDefinition()) return; for (const auto &B : Record->bases()) { QualType BaseType = B.getType(); // Don't look into dependent bases, because name lookup can't look // there anyway. if (BaseType->isDependentType()) continue; const RecordType *Record = BaseType->getAs(); if (!Record) continue; // FIXME: It would be nice to be able to determine whether referencing // a particular member would be ambiguous. For example, given // // struct A { int member; }; // struct B { int member; }; // struct C : A, B { }; // // void f(C *c) { c->### } // // accessing 'member' would result in an ambiguity. However, we // could be smart enough to qualify the member with the base // class, e.g., // // c->B::member // // or // // c->A::member // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, true, Consumer, Visited); } } // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast(Ctx)) { // Traverse categories. for (auto *Cat : IFace->visible_categories()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse protocols. for (auto *I : IFace->all_referenced_protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse the superclass. if (IFace->getSuperClass()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } // If there is an implementation, traverse it. We do this to find // synthesized ivars. if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(IFace->getImplementation(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } else if (ObjCProtocolDecl *Protocol = dyn_cast(Ctx)) { for (auto *I : Protocol->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast(Ctx)) { for (auto *I : Category->protocols()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Category->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); } } } static void LookupVisibleDecls(Scope *S, LookupResult &Result, UnqualUsingDirectiveSet &UDirs, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { if (!S) return; if (!S->getEntity() || (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) || (S->getEntity())->isFunctionOrMethod()) { FindLocalExternScope FindLocals(Result); // Walk through the declarations in this Scope. for (auto *D : S->decls()) { if (NamedDecl *ND = dyn_cast(D)) if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); Visited.add(ND); } } } // FIXME: C++ [temp.local]p8 DeclContext *Entity = nullptr; if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. Entity = S->getEntity(); DeclContext *OuterCtx = findOuterContext(S).first; // FIXME for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast(Ctx)) { if (Method->isInstanceMethod()) { // For instance methods, look for ivars in the method's interface. LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } // We've already performed all of the name lookup that we need // to for Objective-C methods; the next context will be the // outer scope. break; } if (Ctx->isFunctionOrMethod()) continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation // unit's declaration context, because the Scope itself won't have all of // the declarations if we loaded a precompiled header. // FIXME: We would like the translation unit's Scope object to point to the // translation unit, so we don't need this special "if" branch. However, // doing so would force the normal C++ name-lookup code to look into the // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } if (Entity) { // Lookup visible declarations in any namespaces found by using // directives. UnqualUsingDirectiveSet::const_iterator UI, UEnd; std::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast(UI->getNominatedNamespace()), Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } // Lookup names in the parent scope. ShadowContextRAII Shadow(Visited); LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; UnqualUsingDirectiveSet UDirs; if (getLangOpts().CPlusPlus) { // Find the first namespace or translation-unit scope. while (S && !isNamespaceOrTranslationUnitScope(S)) S = S->getParent(); UDirs.visitScopeChain(Initial, S); } UDirs.done(); // Look for visible declarations. LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); Result.setAllowHidden(Consumer.includeHiddenDecls()); VisibleDeclsRecord Visited; if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. /// If GnuLabelLoc is a valid source location, then this is a definition /// of an __label__ label name, otherwise it is a normal label definition /// or use. LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, SourceLocation GnuLabelLoc) { // Do a lookup to see if we have a label with this name already. NamedDecl *Res = nullptr; if (GnuLabelLoc.isValid()) { // Local label definitions always shadow existing labels. Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc); Scope *S = CurScope; PushOnScopeChains(Res, S, true); return cast(Res); } // Not a GNU local label. Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); // If we found a label, check to see if it is in the same context as us. // When in a Block, we don't want to reuse a label in an enclosing function. if (Res && Res->getDeclContext() != CurContext) Res = nullptr; if (!Res) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); Scope *S = CurScope->getFnParent(); assert(S && "Not in a function?"); PushOnScopeChains(Res, S, true); } return cast(Res); } //===----------------------------------------------------------------------===// // Typo correction //===----------------------------------------------------------------------===// static bool isCandidateViable(CorrectionCandidateCallback &CCC, TypoCorrection &Candidate) { Candidate.setCallbackDistance(CCC.RankCandidate(Candidate)); return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance; } static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, IdentifierInfo *Name, Scope *S, CXXScopeSpec *SS, DeclContext *MemberContext, bool EnteringContext, bool isObjCIvarLookup, bool FindHidden); /// \brief Check whether the declarations found for a typo correction are /// visible, and if none of them are, convert the correction to an 'import /// a module' correction. static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { if (TC.begin() == TC.end()) return; TypoCorrection::decl_iterator DI = TC.begin(), DE = TC.end(); for (/**/; DI != DE; ++DI) if (!LookupResult::isVisible(SemaRef, *DI)) break; // Nothing to do if all decls are visible. if (DI == DE) return; llvm::SmallVector NewDecls(TC.begin(), DI); bool AnyVisibleDecls = !NewDecls.empty(); for (/**/; DI != DE; ++DI) { NamedDecl *VisibleDecl = *DI; if (!LookupResult::isVisible(SemaRef, *DI)) VisibleDecl = findAcceptableDecl(SemaRef, *DI); if (VisibleDecl) { if (!AnyVisibleDecls) { // Found a visible decl, discard all hidden ones. AnyVisibleDecls = true; NewDecls.clear(); } NewDecls.push_back(VisibleDecl); } else if (!AnyVisibleDecls && !(*DI)->isModulePrivate()) NewDecls.push_back(*DI); } if (NewDecls.empty()) TC = TypoCorrection(); else { TC.setCorrectionDecls(NewDecls); TC.setRequiresImport(!AnyVisibleDecls); } } // Fill the supplied vector with the IdentifierInfo pointers for each piece of // the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", // fill the vector with the IdentifierInfo pointers for "foo" and "bar"). static void getNestedNameSpecifierIdentifiers( NestedNameSpecifier *NNS, SmallVectorImpl &Identifiers) { if (NestedNameSpecifier *Prefix = NNS->getPrefix()) getNestedNameSpecifierIdentifiers(Prefix, Identifiers); else Identifiers.clear(); const IdentifierInfo *II = nullptr; switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: II = NNS->getAsIdentifier(); break; case NestedNameSpecifier::Namespace: if (NNS->getAsNamespace()->isAnonymousNamespace()) return; II = NNS->getAsNamespace()->getIdentifier(); break; case NestedNameSpecifier::NamespaceAlias: II = NNS->getAsNamespaceAlias()->getIdentifier(); break; case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier(); break; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: return; } if (II) Identifiers.push_back(II); } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; // Only consider entities with identifiers for names, ignoring // special names (constructors, overloaded operators, selectors, // etc.). IdentifierInfo *Name = ND->getIdentifier(); if (!Name) return; // Only consider visible declarations and declarations from modules with // names that exactly match. if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo && !findAcceptableDecl(SemaRef, ND)) return; FoundName(Name->getName()); } void TypoCorrectionConsumer::FoundName(StringRef Name) { // Compute the edit distance between the typo and the name of this // entity, and add the identifier to the list of results. addName(Name, nullptr); } void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword, // and add the keyword to the list of results. addName(Keyword, nullptr, nullptr, true); } void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS, bool isKeyword) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. StringRef TypoStr = Typo->getName(); unsigned MinED = abs((int)Name.size() - (int)TypoStr.size()); if (MinED && TypoStr.size() / MinED < 3) return; // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. unsigned UpperBound = (TypoStr.size() + 2) / 3 + 1; unsigned ED = TypoStr.edit_distance(Name, true, UpperBound); if (ED >= UpperBound) return; TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED); if (isKeyword) TC.makeKeyword(); TC.setCorrectionRange(nullptr, Result.getLookupNameInfo()); addCorrection(TC); } static const unsigned MaxTypoDistanceResultSets = 5; void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { StringRef TypoStr = Typo->getName(); StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); // For very short typos, ignore potential corrections that have a different // base identifier from the typo or which have a normalized edit distance // longer than the typo itself. if (TypoStr.size() < 3 && (Name != TypoStr || Correction.getEditDistance(true) > TypoStr.size())) return; // If the correction is resolved but is not viable, ignore it. if (Correction.isResolved()) { checkCorrectionVisibility(SemaRef, Correction); if (!Correction || !isCandidateViable(*CorrectionValidator, Correction)) return; } TypoResultList &CList = CorrectionResults[Correction.getEditDistance(false)][Name]; if (!CList.empty() && !CList.back().isResolved()) CList.pop_back(); if (NamedDecl *NewND = Correction.getCorrectionDecl()) { std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts()); for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end(); RI != RIEnd; ++RI) { // If the Correction refers to a decl already in the result list, // replace the existing result if the string representation of Correction // comes before the current result alphabetically, then stop as there is // nothing more to be done to add Correction to the candidate set. if (RI->getCorrectionDecl() == NewND) { if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts())) *RI = Correction; return; } } } if (CList.empty() || Correction.isResolved()) CList.push_back(Correction); while (CorrectionResults.size() > MaxTypoDistanceResultSets) CorrectionResults.erase(std::prev(CorrectionResults.end())); } void TypoCorrectionConsumer::addNamespaces( const llvm::MapVector &KnownNamespaces) { SearchNamespaces = true; for (auto KNPair : KnownNamespaces) Namespaces.addNameSpecifier(KNPair.first); bool SSIsTemplate = false; if (NestedNameSpecifier *NNS = (SS && SS->isValid()) ? SS->getScopeRep() : nullptr) { if (const Type *T = NNS->getAsType()) SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization; } for (const auto *TI : SemaRef.getASTContext().types()) { if (CXXRecordDecl *CD = TI->getAsCXXRecordDecl()) { CD = CD->getCanonicalDecl(); if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && !CD->isUnion() && CD->getIdentifier() && (SSIsTemplate || !isa(CD)) && (CD->isBeingDefined() || CD->isCompleteDefinition())) Namespaces.addNameSpecifier(CD); } } } const TypoCorrection &TypoCorrectionConsumer::getNextCorrection() { if (++CurrentTCIndex < ValidatedCorrections.size()) return ValidatedCorrections[CurrentTCIndex]; CurrentTCIndex = ValidatedCorrections.size(); while (!CorrectionResults.empty()) { auto DI = CorrectionResults.begin(); if (DI->second.empty()) { CorrectionResults.erase(DI); continue; } auto RI = DI->second.begin(); if (RI->second.empty()) { DI->second.erase(RI); performQualifiedLookups(); continue; } TypoCorrection TC = RI->second.pop_back_val(); if (TC.isResolved() || TC.requiresImport() || resolveCorrection(TC)) { ValidatedCorrections.push_back(TC); return ValidatedCorrections[CurrentTCIndex]; } } return ValidatedCorrections[0]; // The empty correction. } bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) { IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo(); DeclContext *TempMemberContext = MemberContext; CXXScopeSpec *TempSS = SS.get(); retry_lookup: LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext, EnteringContext, CorrectionValidator->IsObjCIvarLookup, Name == Typo && !Candidate.WillReplaceSpecifier()); switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundUnresolvedValue: if (TempSS) { // Immediately retry the lookup without the given CXXScopeSpec TempSS = nullptr; Candidate.WillReplaceSpecifier(true); goto retry_lookup; } if (TempMemberContext) { if (SS && !TempSS) TempSS = SS.get(); TempMemberContext = nullptr; goto retry_lookup; } if (SearchNamespaces) QualifiedResults.push_back(Candidate); break; case LookupResult::Ambiguous: // We don't deal with ambiguities. break; case LookupResult::Found: case LookupResult::FoundOverloaded: // Store all of the Decls for overloaded symbols for (auto *TRD : Result) Candidate.addCorrectionDecl(TRD); checkCorrectionVisibility(SemaRef, Candidate); if (!isCandidateViable(*CorrectionValidator, Candidate)) { if (SearchNamespaces) QualifiedResults.push_back(Candidate); break; } Candidate.setCorrectionRange(SS.get(), Result.getLookupNameInfo()); return true; } return false; } void TypoCorrectionConsumer::performQualifiedLookups() { unsigned TypoLen = Typo->getName().size(); for (auto QR : QualifiedResults) { for (auto NSI : Namespaces) { DeclContext *Ctx = NSI.DeclCtx; const Type *NSType = NSI.NameSpecifier->getAsType(); // If the current NestedNameSpecifier refers to a class and the // current correction candidate is the name of that class, then skip // it as it is unlikely a qualified version of the class' constructor // is an appropriate correction. if (CXXRecordDecl *NSDecl = NSType ? NSType->getAsCXXRecordDecl() : 0) { if (NSDecl->getIdentifier() == QR.getCorrectionAsIdentifierInfo()) continue; } TypoCorrection TC(QR); TC.ClearCorrectionDecls(); TC.setCorrectionSpecifier(NSI.NameSpecifier); TC.setQualifierDistance(NSI.EditDistance); TC.setCallbackDistance(0); // Reset the callback distance // If the current correction candidate and namespace combination are // too far away from the original typo based on the normalized edit // distance, then skip performing a qualified name lookup. unsigned TmpED = TC.getEditDistance(true); if (QR.getCorrectionAsIdentifierInfo() != Typo && TmpED && TypoLen / TmpED < 3) continue; Result.clear(); Result.setLookupName(QR.getCorrectionAsIdentifierInfo()); if (!SemaRef.LookupQualifiedName(Result, Ctx)) continue; // Any corrections added below will be validated in subsequent // iterations of the main while() loop over the Consumer's contents. switch (Result.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: { if (SS && SS->isValid()) { std::string NewQualified = TC.getAsString(SemaRef.getLangOpts()); std::string OldQualified; llvm::raw_string_ostream OldOStream(OldQualified); SS->getScopeRep()->print(OldOStream, SemaRef.getPrintingPolicy()); OldOStream << Typo->getName(); // If correction candidate would be an identical written qualified // identifer, then the existing CXXScopeSpec probably included a // typedef that didn't get accounted for properly. if (OldOStream.str() == NewQualified) break; } for (LookupResult::iterator TRD = Result.begin(), TRDEnd = Result.end(); TRD != TRDEnd; ++TRD) { if (SemaRef.CheckMemberAccess(TC.getCorrectionRange().getBegin(), NSType ? NSType->getAsCXXRecordDecl() : nullptr, TRD.getPair()) == Sema::AR_accessible) TC.addCorrectionDecl(*TRD); } if (TC.isResolved()) { TC.setCorrectionRange(SS.get(), Result.getLookupNameInfo()); addCorrection(TC); } break; } case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: case LookupResult::FoundUnresolvedValue: break; } } } QualifiedResults.clear(); } TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec) : Context(Context), CurContextChain(buildContextChain(CurContext)), isSorted(false) { if (NestedNameSpecifier *NNS = CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) { llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier); NNS->print(SpecifierOStream, Context.getPrintingPolicy()); getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers); } // Build the list of identifiers that would be used for an absolute // (from the global context) NestedNameSpecifier referring to the current // context. for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), CEnd = CurContextChain.rend(); C != CEnd; ++C) { if (NamespaceDecl *ND = dyn_cast_or_null(*C)) CurContextIdentifiers.push_back(ND->getIdentifier()); } // Add the global context as a NestedNameSpecifier Distances.insert(1); SpecifierInfo SI = {cast(Context.getTranslationUnitDecl()), NestedNameSpecifier::GlobalSpecifier(Context), 1}; DistanceMap[1].push_back(SI); } auto TypoCorrectionConsumer::NamespaceSpecifierSet::buildContextChain( DeclContext *Start) -> DeclContextList { assert(Start && "Building a context chain from a null context"); DeclContextList Chain; for (DeclContext *DC = Start->getPrimaryContext(); DC != nullptr; DC = DC->getLookupParent()) { NamespaceDecl *ND = dyn_cast_or_null(DC); if (!DC->isInlineNamespace() && !DC->isTransparentContext() && !(ND && ND->isAnonymousNamespace())) Chain.push_back(DC->getPrimaryContext()); } return Chain; } void TypoCorrectionConsumer::NamespaceSpecifierSet::sortNamespaces() { SmallVector sortedDistances; sortedDistances.append(Distances.begin(), Distances.end()); if (sortedDistances.size() > 1) std::sort(sortedDistances.begin(), sortedDistances.end()); Specifiers.clear(); for (auto D : sortedDistances) { SpecifierInfoList &SpecList = DistanceMap[D]; Specifiers.append(SpecList.begin(), SpecList.end()); } isSorted = true; } unsigned TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( DeclContextList &DeclChain, NestedNameSpecifier *&NNS) { unsigned NumSpecifiers = 0; for (DeclContextList::reverse_iterator C = DeclChain.rbegin(), CEnd = DeclChain.rend(); C != CEnd; ++C) { if (NamespaceDecl *ND = dyn_cast_or_null(*C)) { NNS = NestedNameSpecifier::Create(Context, NNS, ND); ++NumSpecifiers; } else if (RecordDecl *RD = dyn_cast_or_null(*C)) { NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(), RD->getTypeForDecl()); ++NumSpecifiers; } } return NumSpecifiers; } void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( DeclContext *Ctx) { NestedNameSpecifier *NNS = nullptr; unsigned NumSpecifiers = 0; DeclContextList NamespaceDeclChain(buildContextChain(Ctx)); DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); // Eliminate common elements from the two DeclContext chains. for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), CEnd = CurContextChain.rend(); C != CEnd && !NamespaceDeclChain.empty() && NamespaceDeclChain.back() == *C; ++C) { NamespaceDeclChain.pop_back(); } // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain NumSpecifiers = buildNestedNameSpecifier(NamespaceDeclChain, NNS); // Add an explicit leading '::' specifier if needed. if (NamespaceDeclChain.empty()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } else if (NamedDecl *ND = dyn_cast_or_null(NamespaceDeclChain.back())) { IdentifierInfo *Name = ND->getIdentifier(); bool SameNameSpecifier = false; if (std::find(CurNameSpecifierIdentifiers.begin(), CurNameSpecifierIdentifiers.end(), Name) != CurNameSpecifierIdentifiers.end()) { std::string NewNameSpecifier; llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier); SmallVector NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); NNS->print(SpecifierOStream, Context.getPrintingPolicy()); SpecifierOStream.flush(); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } if (SameNameSpecifier || std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), Name) != CurContextIdentifiers.end()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } } // If the built NestedNameSpecifier would be replacing an existing // NestedNameSpecifier, use the number of component identifiers that // would need to be changed as the edit distance instead of the number // of components in the built NestedNameSpecifier. if (NNS && !CurNameSpecifierIdentifiers.empty()) { SmallVector NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); NumSpecifiers = llvm::ComputeEditDistance( llvm::makeArrayRef(CurNameSpecifierIdentifiers), llvm::makeArrayRef(NewNameSpecifierIdentifiers)); } isSorted = false; Distances.insert(NumSpecifiers); SpecifierInfo SI = {Ctx, NNS, NumSpecifiers}; DistanceMap[NumSpecifiers].push_back(SI); } /// \brief Perform name lookup for a possible result for typo correction. static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, IdentifierInfo *Name, Scope *S, CXXScopeSpec *SS, DeclContext *MemberContext, bool EnteringContext, bool isObjCIvarLookup, bool FindHidden) { Res.suppressDiagnostics(); Res.clear(); Res.setLookupName(Name); Res.setAllowHidden(FindHidden); if (MemberContext) { if (ObjCInterfaceDecl *Class = dyn_cast(MemberContext)) { if (isObjCIvarLookup) { if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) { Res.addDecl(Ivar); Res.resolveKind(); return; } } if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) { Res.addDecl(Prop); Res.resolveKind(); return; } } SemaRef.LookupQualifiedName(Res, MemberContext); return; } SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); // Fake ivar lookup; this should really be part of // LookupParsedName. if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { if (Method->isInstanceMethod() && Method->getClassInterface() && (Res.empty() || (Res.isSingleResult() && Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) { if (ObjCIvarDecl *IV = Method->getClassInterface()->lookupInstanceVariable(Name)) { Res.addDecl(IV); Res.resolveKind(); } } } } /// \brief Add keywords to the consumer as possible typo corrections. static void AddKeywordsToConsumer(Sema &SemaRef, TypoCorrectionConsumer &Consumer, Scope *S, CorrectionCandidateCallback &CCC, bool AfterNestedNameSpecifier) { if (AfterNestedNameSpecifier) { // For 'X::', we know exactly which keywords can appear next. Consumer.addKeywordResult("template"); if (CCC.WantExpressionKeywords) Consumer.addKeywordResult("operator"); return; } if (CCC.WantObjCSuper) Consumer.addKeywordResult("super"); if (CCC.WantTypeSpecifiers) { // Add type-specifier keywords to the set of results. static const char *const CTypeSpecs[] = { "char", "const", "double", "enum", "float", "int", "long", "short", "signed", "struct", "union", "unsigned", "void", "volatile", "_Complex", "_Imaginary", // storage-specifiers as well "extern", "inline", "static", "typedef" }; const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs); for (unsigned I = 0; I != NumCTypeSpecs; ++I) Consumer.addKeywordResult(CTypeSpecs[I]); if (SemaRef.getLangOpts().C99) Consumer.addKeywordResult("restrict"); if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus) Consumer.addKeywordResult("bool"); else if (SemaRef.getLangOpts().C99) Consumer.addKeywordResult("_Bool"); if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("class"); Consumer.addKeywordResult("typename"); Consumer.addKeywordResult("wchar_t"); if (SemaRef.getLangOpts().CPlusPlus11) { Consumer.addKeywordResult("char16_t"); Consumer.addKeywordResult("char32_t"); Consumer.addKeywordResult("constexpr"); Consumer.addKeywordResult("decltype"); Consumer.addKeywordResult("thread_local"); } } if (SemaRef.getLangOpts().GNUMode) Consumer.addKeywordResult("typeof"); } else if (CCC.WantFunctionLikeCasts) { static const char *const CastableTypeSpecs[] = { "char", "double", "float", "int", "long", "short", "signed", "unsigned", "void" }; for (auto *kw : CastableTypeSpecs) Consumer.addKeywordResult(kw); } if (CCC.WantCXXNamedCasts && SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("const_cast"); Consumer.addKeywordResult("dynamic_cast"); Consumer.addKeywordResult("reinterpret_cast"); Consumer.addKeywordResult("static_cast"); } if (CCC.WantExpressionKeywords) { Consumer.addKeywordResult("sizeof"); if (SemaRef.getLangOpts().Bool || SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("false"); Consumer.addKeywordResult("true"); } if (SemaRef.getLangOpts().CPlusPlus) { static const char *const CXXExprs[] = { "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs); for (unsigned I = 0; I != NumCXXExprs; ++I) Consumer.addKeywordResult(CXXExprs[I]); if (isa(SemaRef.CurContext) && cast(SemaRef.CurContext)->isInstance()) Consumer.addKeywordResult("this"); if (SemaRef.getLangOpts().CPlusPlus11) { Consumer.addKeywordResult("alignof"); Consumer.addKeywordResult("nullptr"); } } if (SemaRef.getLangOpts().C11) { // FIXME: We should not suggest _Alignof if the alignof macro // is present. Consumer.addKeywordResult("_Alignof"); } } if (CCC.WantRemainingKeywords) { if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) { // Statements. static const char *const CStmts[] = { "do", "else", "for", "goto", "if", "return", "switch", "while" }; const unsigned NumCStmts = llvm::array_lengthof(CStmts); for (unsigned I = 0; I != NumCStmts; ++I) Consumer.addKeywordResult(CStmts[I]); if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("catch"); Consumer.addKeywordResult("try"); } if (S && S->getBreakParent()) Consumer.addKeywordResult("break"); if (S && S->getContinueParent()) Consumer.addKeywordResult("continue"); if (!SemaRef.getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult("case"); Consumer.addKeywordResult("default"); } } else { if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("namespace"); Consumer.addKeywordResult("template"); } if (S && S->isClassScope()) { Consumer.addKeywordResult("explicit"); Consumer.addKeywordResult("friend"); Consumer.addKeywordResult("mutable"); Consumer.addKeywordResult("private"); Consumer.addKeywordResult("protected"); Consumer.addKeywordResult("public"); Consumer.addKeywordResult("virtual"); } } if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("using"); if (SemaRef.getLangOpts().CPlusPlus11) Consumer.addKeywordResult("static_assert"); } } } std::unique_ptr Sema::makeTypoCorrectionConsumer( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery) { if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking || DisableTypoCorrection) return nullptr; // In Microsoft mode, don't perform typo correction in a template member // function dependent context because it interferes with the "lookup into // dependent bases of class templates" feature. if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && isa(CurContext)) return nullptr; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) return nullptr; // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) return nullptr; // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) return nullptr; // Don't try to correct 'super'. if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) return nullptr; // Abort if typo correction already failed for this specific typo. IdentifierSourceLocations::iterator locs = TypoCorrectionFailures.find(Typo); if (locs != TypoCorrectionFailures.end() && locs->second.count(TypoName.getLoc())) return nullptr; // Don't try to correct the identifier "vector" when in AltiVec mode. // TODO: Figure out why typo correction misbehaves in this case, fix it, and // remove this workaround. if (getLangOpts().AltiVec && Typo->isStr("vector")) return nullptr; // Provide a stop gap for files that are just seriously broken. Trying // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. unsigned Limit = getDiagnostics().getDiagnosticOptions().SpellCheckingLimit; if (Limit && TyposCorrected >= Limit) return nullptr; ++TyposCorrected; // If we're handling a missing symbol error, using modules, and the // special search all modules option is used, look for a missing import. if (ErrorRecovery && getLangOpts().Modules && getLangOpts().ModulesSearchAll) { // The following has the side effect of loading the missing module. getModuleLoader().lookupMissingImports(Typo->getName(), TypoName.getLocStart()); } CorrectionCandidateCallback &CCCRef = *CCC; auto Consumer = llvm::make_unique( *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext); // Perform name lookup to find visible, similarly-named entities. bool IsUnqualifiedLookup = false; DeclContext *QualifiedDC = MemberContext; if (MemberContext) { LookupVisibleDecls(MemberContext, LookupKind, *Consumer); // Look in qualified interfaces. if (OPT) { for (auto *I : OPT->quals()) LookupVisibleDecls(I, LookupKind, *Consumer); } } else if (SS && SS->isSet()) { QualifiedDC = computeDeclContext(*SS, EnteringContext); if (!QualifiedDC) return nullptr; LookupVisibleDecls(QualifiedDC, LookupKind, *Consumer); } else { IsUnqualifiedLookup = true; } // Determine whether we are going to search in the various namespaces for // corrections. bool SearchNamespaces = getLangOpts().CPlusPlus && (IsUnqualifiedLookup || (SS && SS->isSet())); if (IsUnqualifiedLookup || SearchNamespaces) { // For unqualified lookup, look through all of the names that we have // seen in this translation unit. // FIXME: Re-add the ability to skip very unlikely potential corrections. for (const auto &I : Context.Idents) Consumer->FoundName(I.getKey()); // Walk through identifiers in external identifier sources. // FIXME: Re-add the ability to skip very unlikely potential corrections. if (IdentifierInfoLookup *External = Context.Idents.getExternalIdentifierLookup()) { std::unique_ptr Iter(External->getIdentifiers()); do { StringRef Name = Iter->Next(); if (Name.empty()) break; Consumer->FoundName(Name); } while (true); } } AddKeywordsToConsumer(*this, *Consumer, S, CCCRef, SS && SS->isNotEmpty()); // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going // to search those namespaces. if (SearchNamespaces) { // Load any externally-known namespaces. if (ExternalSource && !LoadedExternalKnownNamespaces) { SmallVector ExternalKnownNamespaces; LoadedExternalKnownNamespaces = true; ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); for (auto *N : ExternalKnownNamespaces) KnownNamespaces[N] = true; } Consumer->addNamespaces(KnownNamespaces); } return Consumer; } /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. /// /// \param TypoName the \c DeclarationNameInfo structure that contains /// the name that was present in the source code along with its location. /// /// \param LookupKind the name-lookup criteria used to search for the name. /// /// \param S the scope in which name lookup occurs. /// /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// /// \param CCC A CorrectionCandidateCallback object that provides further /// validation of typo correction candidates. It also provides flags for /// determining the set of keywords permitted. /// /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// /// \returns a \c TypoCorrection containing the corrected name if the typo /// along with information such as the \c NamedDecl where the corrected name /// was declared, and any additional \c NestedNameSpecifier needed to access /// it (C++ only). The \c TypoCorrection is empty if there is no correction. TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool RecordFailure) { assert(CCC && "CorrectTypo requires a CorrectionCandidateCallback"); // Always let the ExternalSource have the first chance at correction, even // if we would otherwise have given up. if (ExternalSource) { if (TypoCorrection Correction = ExternalSource->CorrectTypo( TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT)) return Correction; } // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for // some instances of CTC_Unknown, while WantRemainingKeywords is true // for CTC_Unknown but not for CTC_ObjCMessageReceiver. bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords; IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, Mode == CTK_ErrorRecovery); if (!Consumer) return TypoCorrection(); // If we haven't found anything, we're done. if (Consumer->empty()) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Make sure the best edit distance (prior to adding any namespace qualifiers) // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); unsigned TypoLen = Typo->getName().size(); if (ED > 0 && TypoLen / ED < 3) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); TypoCorrection BestTC = Consumer->getNextCorrection(); TypoCorrection SecondBestTC = Consumer->getNextCorrection(); if (!BestTC) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); ED = BestTC.getEditDistance(); if (TypoLen >= 3 && ED > 0 && TypoLen / ED < 3) { // If this was an unqualified lookup and we believe the callback // object wouldn't have filtered out possible corrections, note // that no correction was found. return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); } // If only a single name remains, return that result. if (!SecondBestTC || SecondBestTC.getEditDistance(false) > BestTC.getEditDistance(false)) { const TypoCorrection &Result = BestTC; // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (ED == 0 && Result.isKeyword()) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); TypoCorrection TC = Result; TC.setCorrectionRange(SS, TypoName); checkCorrectionVisibility(*this, TC); return TC; } else if (SecondBestTC && ObjCMessageReceiver) { // Prefer 'super' when we're completing in a message-receiver // context. if (BestTC.getCorrection().getAsString() != "super") { if (SecondBestTC.getCorrection().getAsString() == "super") BestTC = SecondBestTC; else if ((*Consumer)["super"].front().isKeyword()) BestTC = (*Consumer)["super"].front(); } // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. if (BestTC.getEditDistance() == 0 || BestTC.getCorrection().getAsString() != "super") return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); BestTC.setCorrectionRange(SS, TypoName); return BestTC; } // Record the failure's location if needed and return an empty correction. If // this was an unqualified lookup and we believe the callback object did not // filter out possible corrections, also cache the failure for the typo. return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); } /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. /// /// \param TypoName the \c DeclarationNameInfo structure that contains /// the name that was present in the source code along with its location. /// /// \param LookupKind the name-lookup criteria used to search for the name. /// /// \param S the scope in which name lookup occurs. /// /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// /// \param CCC A CorrectionCandidateCallback object that provides further /// validation of typo correction candidates. It also provides flags for /// determining the set of keywords permitted. /// /// \param TDG A TypoDiagnosticGenerator functor that will be used to print /// diagnostics when the actual typo correction is attempted. /// /// \param TRC A TypoRecoveryCallback functor that will be used to build an /// Expr from a typo correction candidate. /// /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// /// \returns a new \c TypoExpr that will later be replaced in the AST with an /// Expr representing the result of performing typo correction, or nullptr if /// typo correction is not possible. If nullptr is returned, no diagnostics will /// be emitted and it is the responsibility of the caller to emit any that are /// needed. TypoExpr *Sema::CorrectTypoDelayed( const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT) { assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); TypoCorrection Empty; auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, /*SearchModules=*/(Mode == CTK_ErrorRecovery) && getLangOpts().Modules && getLangOpts().ModulesSearchAll); if (!Consumer || Consumer->empty()) return nullptr; // Make sure the best edit distance (prior to adding any namespace qualifiers) // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (ED > 0 && Typo->getName().size() / ED < 3) return nullptr; ExprEvalContexts.back().NumTypos++; return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { if (!CDecl) return; if (isKeyword()) CorrectionDecls.clear(); CorrectionDecls.push_back(CDecl->getUnderlyingDecl()); if (!CorrectionName) CorrectionName = CDecl->getDeclName(); } std::string TypoCorrection::getAsString(const LangOptions &LO) const { if (CorrectionNameSpec) { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); PrefixOStream << CorrectionName; return PrefixOStream.str(); } return CorrectionName.getAsString(); } bool CorrectionCandidateCallback::ValidateCandidate( const TypoCorrection &candidate) { if (!candidate.isResolved()) return true; if (candidate.isKeyword()) return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts || WantRemainingKeywords || WantObjCSuper; bool HasNonType = false; bool HasStaticMethod = false; bool HasNonStaticMethod = false; for (Decl *D : candidate) { if (FunctionTemplateDecl *FTD = dyn_cast(D)) D = FTD->getTemplatedDecl(); if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isStatic()) HasStaticMethod = true; else HasNonStaticMethod = true; } if (!isa(D)) HasNonType = true; } if (IsAddressOfOperand && HasNonStaticMethod && !HasStaticMethod && !candidate.getCorrectionSpecifier()) return false; return WantTypeSpecifiers || HasNonType; } FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, MemberExpr *ME) : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs), CurContext(SemaRef.CurContext), MemberFn(ME) { WantTypeSpecifiers = false; WantFunctionLikeCasts = SemaRef.getLangOpts().CPlusPlus && NumArgs == 1; WantRemainingKeywords = false; } bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { if (!candidate.getCorrectionDecl()) return candidate.isKeyword(); for (auto *C : candidate) { FunctionDecl *FD = nullptr; NamedDecl *ND = C->getUnderlyingDecl(); if (FunctionTemplateDecl *FTD = dyn_cast(ND)) FD = FTD->getTemplatedDecl(); if (!HasExplicitTemplateArgs && !FD) { if (!(FD = dyn_cast(ND)) && isa(ND)) { // If the Decl is neither a function nor a template function, // determine if it is a pointer or reference to a function. If so, // check against the number of arguments expected for the pointee. QualType ValType = cast(ND)->getType(); if (ValType->isAnyPointerType() || ValType->isReferenceType()) ValType = ValType->getPointeeType(); if (const FunctionProtoType *FPT = ValType->getAs()) if (FPT->getNumParams() == NumArgs) return true; } } // Skip the current candidate if it is not a FunctionDecl or does not accept // the current number of arguments. if (!FD || !(FD->getNumParams() >= NumArgs && FD->getMinRequiredArguments() <= NumArgs)) continue; // If the current candidate is a non-static C++ method, skip the candidate // unless the method being corrected--or the current DeclContext, if the // function being corrected is not a method--is a method in the same class // or a descendent class of the candidate's parent class. if (CXXMethodDecl *MD = dyn_cast(FD)) { if (MemberFn || !MD->isStatic()) { CXXMethodDecl *CurMD = MemberFn ? dyn_cast_or_null(MemberFn->getMemberDecl()) : dyn_cast_or_null(CurContext); CXXRecordDecl *CurRD = CurMD ? CurMD->getParent()->getCanonicalDecl() : nullptr; CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); if (!CurRD || (CurRD != RD && !CurRD->isDerivedFrom(RD))) continue; } } return true; } return false; } void Sema::diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery) { diagnoseTypo(Correction, TypoDiag, PDiag(diag::note_previous_decl), ErrorRecovery); } /// Find which declaration we should import to provide the definition of /// the given declaration. static const NamedDecl *getDefinitionToImport(const NamedDecl *D) { if (const VarDecl *VD = dyn_cast(D)) return VD->getDefinition(); if (const FunctionDecl *FD = dyn_cast(D)) return FD->isDefined(FD) ? FD : nullptr; if (const TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); if (const ObjCInterfaceDecl *ID = dyn_cast(D)) return ID->getDefinition(); if (const ObjCProtocolDecl *PD = dyn_cast(D)) return PD->getDefinition(); if (const TemplateDecl *TD = dyn_cast(D)) return getDefinitionToImport(TD->getTemplatedDecl()); return nullptr; } /// \brief Diagnose a successfully-corrected typo. Separated from the correction /// itself to allow external validation of the result, etc. /// /// \param Correction The result of performing typo correction. /// \param TypoDiag The diagnostic to produce. This will have the corrected /// string added to it (and usually also a fixit). /// \param PrevNote A note to use when indicating the location of the entity to /// which we are correcting. Will have the correction string added to it. /// \param ErrorRecovery If \c true (the default), the caller is going to /// recover from the typo as if the corrected string had been typed. /// In this case, \c PDiag must be an error, and we will attach a fixit /// to it. void Sema::diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery) { std::string CorrectedStr = Correction.getAsString(getLangOpts()); std::string CorrectedQuotedStr = Correction.getQuoted(getLangOpts()); FixItHint FixTypo = FixItHint::CreateReplacement( Correction.getCorrectionRange(), CorrectedStr); // Maybe we're just missing a module import. if (Correction.requiresImport()) { NamedDecl *Decl = Correction.getCorrectionDecl(); assert(Decl && "import required but no declaration to import"); // Suggest importing a module providing the definition of this entity, if // possible. const NamedDecl *Def = getDefinitionToImport(Decl); if (!Def) Def = Decl; Module *Owner = Def->getOwningModule(); assert(Owner && "definition of hidden declaration is not in a module"); Diag(Correction.getCorrectionRange().getBegin(), diag::err_module_private_declaration) << Def << Owner->getFullModuleName(); Diag(Def->getLocation(), diag::note_previous_declaration); // Recover by implicitly importing this module. if (ErrorRecovery) createImplicitModuleImportForErrorRecovery( Correction.getCorrectionRange().getBegin(), Owner); return; } Diag(Correction.getCorrectionRange().getBegin(), TypoDiag) << CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint()); NamedDecl *ChosenDecl = Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl(); if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); } TypoExpr *Sema::createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC) { assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); auto TE = new (Context) TypoExpr(Context.DependentTy); auto &State = DelayedTypos[TE]; State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); State.RecoveryHandler = std::move(TRC); return TE; } const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const { auto Entry = DelayedTypos.find(TE); assert(Entry != DelayedTypos.end() && "Failed to get the state for a TypoExpr!"); return Entry->second; } void Sema::clearDelayedTypo(TypoExpr *TE) { DelayedTypos.erase(TE); } Index: vendor/clang/dist/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- vendor/clang/dist/lib/Serialization/ASTWriterDecl.cpp (revision 278753) +++ vendor/clang/dist/lib/Serialization/ASTWriterDecl.cpp (revision 278754) @@ -1,2036 +1,2036 @@ //===--- ASTWriterDecl.cpp - Declaration Serialization --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements serialization for Declarations. // //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" #include "ASTCommon.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/Basic/SourceManager.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace serialization; //===----------------------------------------------------------------------===// // Declaration serialization //===----------------------------------------------------------------------===// namespace clang { class ASTDeclWriter : public DeclVisitor { ASTWriter &Writer; ASTContext &Context; typedef ASTWriter::RecordData RecordData; RecordData &Record; public: serialization::DeclCode Code; unsigned AbbrevToUse; ASTDeclWriter(ASTWriter &Writer, ASTContext &Context, RecordData &Record) : Writer(Writer), Context(Context), Record(Record) { } void Visit(Decl *D); void VisitDecl(Decl *D); void VisitTranslationUnitDecl(TranslationUnitDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitLabelDecl(LabelDecl *LD); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *D); void VisitTypedefNameDecl(TypedefNameDecl *D); void VisitTypedefDecl(TypedefDecl *D); void VisitTypeAliasDecl(TypeAliasDecl *D); void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *D); void VisitEnumDecl(EnumDecl *D); void VisitRecordDecl(RecordDecl *D); void VisitCXXRecordDecl(CXXRecordDecl *D); void VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); void VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *D); void VisitFunctionDecl(FunctionDecl *D); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitMSPropertyDecl(MSPropertyDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); void VisitCapturedDecl(CapturedDecl *D); void VisitEmptyDecl(EmptyDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset); template void VisitRedeclarable(Redeclarable *D); // FIXME: Put in the same order is DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); void VisitObjCProtocolDecl(ObjCProtocolDecl *D); void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); void VisitObjCCategoryDecl(ObjCCategoryDecl *D); void VisitObjCImplDecl(ObjCImplDecl *D); void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); void VisitObjCImplementationDecl(ObjCImplementationDecl *D); void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); void AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); if (auto *CD = dyn_cast(FD)) Writer.AddCXXCtorInitializers(CD->CtorInitializers, CD->NumCtorInitializers, Record); Writer.AddStmt(FD->getBody()); } }; } void ASTDeclWriter::Visit(Decl *D) { DeclVisitor::Visit(D); // Source locations require array (variable-length) abbreviations. The // abbreviation infrastructure requires that arrays are encoded last, so // we handle it here in the case of those classes derived from DeclaratorDecl if (DeclaratorDecl *DD = dyn_cast(D)){ Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record); } // Handle FunctionDecl's body here and write it after all other Stmts/Exprs // have been written. We want it last because we will not read it back when // retrieving it from the AST, we'll just lazily set the offset. if (FunctionDecl *FD = dyn_cast(D)) { Record.push_back(FD->doesThisDeclarationHaveABody()); if (FD->doesThisDeclarationHaveABody()) Writer.AddStmt(FD->getBody()); } } void ASTDeclWriter::VisitDecl(Decl *D) { Writer.AddDeclRef(cast_or_null(D->getDeclContext()), Record); Writer.AddDeclRef(cast_or_null(D->getLexicalDeclContext()), Record); Record.push_back(D->isInvalidDecl()); Record.push_back(D->hasAttrs()); if (D->hasAttrs()) Writer.WriteAttributes(llvm::makeArrayRef(D->getAttrs().begin(), D->getAttrs().size()), Record); Record.push_back(D->isImplicit()); Record.push_back(D->isUsed(false)); Record.push_back(D->isReferenced()); Record.push_back(D->isTopLevelDeclInObjCContainer()); Record.push_back(D->getAccess()); Record.push_back(D->isModulePrivate()); Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation())); // If this declaration injected a name into a context different from its // lexical context, and that context is an imported namespace, we need to // update its visible declarations to include this name. // // This happens when we instantiate a class with a friend declaration or a // function with a local extern declaration, for instance. if (D->isOutOfLine()) { auto *DC = D->getDeclContext(); while (auto *NS = dyn_cast(DC->getRedeclContext())) { if (!NS->isFromASTFile()) break; Writer.AddUpdatedDeclContext(NS->getPrimaryContext()); if (!NS->isInlineNamespace()) break; DC = NS->getParent(); } } } void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { llvm_unreachable("Translation units aren't directly serialized"); } void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) { VisitDecl(D); Writer.AddDeclarationName(D->getDeclName(), Record); if (needsAnonymousDeclarationNumber(D)) Record.push_back(Writer.getAnonymousDeclarationNumber(D)); } void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); } void ASTDeclWriter::VisitTypedefNameDecl(TypedefNameDecl *D) { VisitRedeclarable(D); VisitTypeDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Record.push_back(D->isModed()); if (D->isModed()) Writer.AddTypeRef(D->getUnderlyingType(), Record); } void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypedefNameDecl(D); if (!D->hasAttrs() && !D->isImplicit() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->isTopLevelDeclInObjCContainer() && !D->isModulePrivate() && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclTypedefAbbrev(); Code = serialization::DECL_TYPEDEF; } void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) { VisitTypedefNameDecl(D); Writer.AddDeclRef(D->getDescribedAliasTemplate(), Record); Code = serialization::DECL_TYPEALIAS; } void ASTDeclWriter::VisitTagDecl(TagDecl *D) { VisitRedeclarable(D); VisitTypeDecl(D); Record.push_back(D->getIdentifierNamespace()); Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding if (!isa(D)) Record.push_back(D->isCompleteDefinition()); Record.push_back(D->isEmbeddedInDeclarator()); Record.push_back(D->isFreeStanding()); Record.push_back(D->isCompleteDefinitionRequired()); Writer.AddSourceLocation(D->getRBraceLoc(), Record); if (D->hasExtInfo()) { Record.push_back(1); Writer.AddQualifierInfo(*D->getExtInfo(), Record); } else if (auto *TD = D->getTypedefNameForAnonDecl()) { Record.push_back(2); Writer.AddDeclRef(TD, Record); Writer.AddIdentifierRef(TD->getDeclName().getAsIdentifierInfo(), Record); } else if (auto *DD = D->getDeclaratorForAnonDecl()) { Record.push_back(3); Writer.AddDeclRef(DD, Record); } else { Record.push_back(0); } } void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeSourceInfo(D->getIntegerTypeSourceInfo(), Record); if (!D->getIntegerTypeSourceInfo()) Writer.AddTypeRef(D->getIntegerType(), Record); Writer.AddTypeRef(D->getPromotionType(), Record); Record.push_back(D->getNumPositiveBits()); Record.push_back(D->getNumNegativeBits()); Record.push_back(D->isScoped()); Record.push_back(D->isScopedUsingClassTag()); Record.push_back(D->isFixed()); if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) { Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record); Record.push_back(MemberInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record); } else { Writer.AddDeclRef(nullptr, Record); } if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && !D->getTypedefNameForAnonDecl() && !D->getDeclaratorForAnonDecl() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclEnumAbbrev(); Code = serialization::DECL_ENUM; } void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { VisitTagDecl(D); Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); Record.push_back(D->hasObjectMember()); Record.push_back(D->hasVolatileMember()); if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->hasExtInfo() && !D->getTypedefNameForAnonDecl() && !D->getDeclaratorForAnonDecl() && D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclRecordAbbrev(); Code = serialization::DECL_RECORD; } void ASTDeclWriter::VisitValueDecl(ValueDecl *D) { VisitNamedDecl(D); Writer.AddTypeRef(D->getType(), Record); } void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { VisitValueDecl(D); Record.push_back(D->getInitExpr()? 1 : 0); if (D->getInitExpr()) Writer.AddStmt(D->getInitExpr()); Writer.AddAPSInt(D->getInitVal(), Record); Code = serialization::DECL_ENUM_CONSTANT; } void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); Writer.AddSourceLocation(D->getInnerLocStart(), Record); Record.push_back(D->hasExtInfo()); if (D->hasExtInfo()) Writer.AddQualifierInfo(*D->getExtInfo(), Record); } void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { VisitRedeclarable(D); VisitDeclaratorDecl(D); Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record); Record.push_back(D->getIdentifierNamespace()); // FunctionDecl's body is handled last at ASTWriterDecl::Visit, // after everything else is written. - Record.push_back(D->getStorageClass()); // FIXME: stable encoding + Record.push_back((int)D->SClass); // FIXME: stable encoding Record.push_back(D->IsInline); - Record.push_back(D->isInlineSpecified()); - Record.push_back(D->isVirtualAsWritten()); - Record.push_back(D->isPure()); - Record.push_back(D->hasInheritedPrototype()); - Record.push_back(D->hasWrittenPrototype()); - Record.push_back(D->isDeletedAsWritten()); - Record.push_back(D->isTrivial()); - Record.push_back(D->isDefaulted()); - Record.push_back(D->isExplicitlyDefaulted()); - Record.push_back(D->hasImplicitReturnZero()); - Record.push_back(D->isConstexpr()); + Record.push_back(D->IsInlineSpecified); + Record.push_back(D->IsVirtualAsWritten); + Record.push_back(D->IsPure); + Record.push_back(D->HasInheritedPrototype); + Record.push_back(D->HasWrittenPrototype); + Record.push_back(D->IsDeleted); + Record.push_back(D->IsTrivial); + Record.push_back(D->IsDefaulted); + Record.push_back(D->IsExplicitlyDefaulted); + Record.push_back(D->HasImplicitReturnZero); + Record.push_back(D->IsConstexpr); Record.push_back(D->HasSkippedBody); - Record.push_back(D->isLateTemplateParsed()); + Record.push_back(D->IsLateTemplateParsed); Record.push_back(D->getLinkageInternal()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: break; case FunctionDecl::TK_FunctionTemplate: Writer.AddDeclRef(D->getDescribedFunctionTemplate(), Record); break; case FunctionDecl::TK_MemberSpecialization: { MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo(); Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record); Record.push_back(MemberInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record); break; } case FunctionDecl::TK_FunctionTemplateSpecialization: { FunctionTemplateSpecializationInfo * FTSInfo = D->getTemplateSpecializationInfo(); Writer.AddDeclRef(FTSInfo->getTemplate(), Record); Record.push_back(FTSInfo->getTemplateSpecializationKind()); // Template arguments. Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record); // Template args as written. Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr); if (FTSInfo->TemplateArgumentsAsWritten) { Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs); for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs; i!=e; ++i) Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i], Record); Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc, Record); Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc, Record); } Writer.AddSourceLocation(FTSInfo->getPointOfInstantiation(), Record); if (D->isCanonicalDecl()) { // Write the template that contains the specializations set. We will // add a FunctionTemplateSpecializationInfo to it when reading. Writer.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl(), Record); } break; } case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { DependentFunctionTemplateSpecializationInfo * DFTSInfo = D->getDependentSpecializationInfo(); // Templates. Record.push_back(DFTSInfo->getNumTemplates()); for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i) Writer.AddDeclRef(DFTSInfo->getTemplate(i), Record); // Templates args. Record.push_back(DFTSInfo->getNumTemplateArgs()); for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) Writer.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i), Record); Writer.AddSourceLocation(DFTSInfo->getLAngleLoc(), Record); Writer.AddSourceLocation(DFTSInfo->getRAngleLoc(), Record); break; } } Record.push_back(D->param_size()); for (auto P : D->params()) Writer.AddDeclRef(P, Record); Code = serialization::DECL_FUNCTION; } void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { VisitNamedDecl(D); // FIXME: convert to LazyStmtPtr? // Unlike C/C++, method bodies will never be in header files. bool HasBodyStuff = D->getBody() != nullptr || D->getSelfDecl() != nullptr || D->getCmdDecl() != nullptr; Record.push_back(HasBodyStuff); if (HasBodyStuff) { Writer.AddStmt(D->getBody()); Writer.AddDeclRef(D->getSelfDecl(), Record); Writer.AddDeclRef(D->getCmdDecl(), Record); } Record.push_back(D->isInstanceMethod()); Record.push_back(D->isVariadic()); Record.push_back(D->isPropertyAccessor()); Record.push_back(D->isDefined()); Record.push_back(D->IsOverriding); Record.push_back(D->HasSkippedBody); Record.push_back(D->IsRedeclaration); Record.push_back(D->HasRedeclaration); if (D->HasRedeclaration) { assert(Context.getObjCMethodRedeclaration(D)); Writer.AddDeclRef(Context.getObjCMethodRedeclaration(D), Record); } // FIXME: stable encoding for @required/@optional Record.push_back(D->getImplementationControl()); // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway Record.push_back(D->getObjCDeclQualifier()); Record.push_back(D->hasRelatedResultType()); Writer.AddTypeRef(D->getReturnType(), Record); Writer.AddTypeSourceInfo(D->getReturnTypeSourceInfo(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->param_size()); for (const auto *P : D->params()) Writer.AddDeclRef(P, Record); Record.push_back(D->SelLocsKind); unsigned NumStoredSelLocs = D->getNumStoredSelLocs(); SourceLocation *SelLocs = D->getStoredSelLocs(); Record.push_back(NumStoredSelLocs); for (unsigned i = 0; i != NumStoredSelLocs; ++i) Writer.AddSourceLocation(SelLocs[i], Record); Code = serialization::DECL_OBJC_METHOD; } void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtStartLoc(), Record); Writer.AddSourceRange(D->getAtEndRange(), Record); // Abstract class (no need to define a stable serialization::DECL code). } void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { VisitRedeclarable(D); VisitObjCContainerDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) { // Write the DefinitionData ObjCInterfaceDecl::DefinitionData &Data = D->data(); Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); Record.push_back(Data.HasDesignatedInitializers); // Write out the protocols that are directly referenced by the @interface. Record.push_back(Data.ReferencedProtocols.size()); for (const auto *P : D->protocols()) Writer.AddDeclRef(P, Record); for (const auto &PL : D->protocol_locs()) Writer.AddSourceLocation(PL, Record); // Write out the protocols that are transitively referenced. Record.push_back(Data.AllReferencedProtocols.size()); for (ObjCList::iterator P = Data.AllReferencedProtocols.begin(), PEnd = Data.AllReferencedProtocols.end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) { // Ensure that we write out the set of categories for this class. Writer.ObjCClassesWithCategories.insert(D); // Make sure that the categories get serialized. for (; Cat; Cat = Cat->getNextClassCategoryRaw()) (void)Writer.GetDeclRef(Cat); } } Code = serialization::DECL_OBJC_INTERFACE; } void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { VisitFieldDecl(D); // FIXME: stable encoding for @public/@private/@protected/@package Record.push_back(D->getAccessControl()); Record.push_back(D->getSynthesize()); if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && !D->isModulePrivate() && !D->getBitWidth() && !D->hasExtInfo() && D->getDeclName()) AbbrevToUse = Writer.getDeclObjCIvarAbbrev(); Code = serialization::DECL_OBJC_IVAR; } void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { VisitRedeclarable(D); VisitObjCContainerDecl(D); Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) { Record.push_back(D->protocol_size()); for (const auto *I : D->protocols()) Writer.AddDeclRef(I, Record); for (const auto &PL : D->protocol_locs()) Writer.AddSourceLocation(PL, Record); } Code = serialization::DECL_OBJC_PROTOCOL; } void ASTDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { VisitFieldDecl(D); Code = serialization::DECL_OBJC_AT_DEFS_FIELD; } void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { VisitObjCContainerDecl(D); Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Writer.AddDeclRef(D->getClassInterface(), Record); Record.push_back(D->protocol_size()); for (const auto *I : D->protocols()) Writer.AddDeclRef(I, Record); for (const auto &PL : D->protocol_locs()) Writer.AddSourceLocation(PL, Record); Code = serialization::DECL_OBJC_CATEGORY; } void ASTDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); Code = serialization::DECL_OBJC_COMPATIBLE_ALIAS; } void ASTDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddSourceLocation(D->getLParenLoc(), Record); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); Record.push_back((unsigned)D->getPropertyAttributesAsWritten()); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyImplementation()); Writer.AddDeclarationName(D->getGetterName(), Record); Writer.AddDeclarationName(D->getSetterName(), Record); Writer.AddDeclRef(D->getGetterMethodDecl(), Record); Writer.AddDeclRef(D->getSetterMethodDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); Code = serialization::DECL_OBJC_PROPERTY; } void ASTDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { VisitObjCContainerDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); // Abstract class (no need to define a stable serialization::DECL code). } void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); Writer.AddIdentifierRef(D->getIdentifier(), Record); Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Code = serialization::DECL_OBJC_CATEGORY_IMPL; } void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Record.push_back(D->hasNonZeroConstructors()); Record.push_back(D->hasDestructors()); Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers, Record); Code = serialization::DECL_OBJC_IMPLEMENTATION; } void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddDeclRef(D->getPropertyDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); Writer.AddSourceLocation(D->getPropertyIvarDeclLoc(), Record); Writer.AddStmt(D->getGetterCXXConstructor()); Writer.AddStmt(D->getSetterCXXAssignment()); Code = serialization::DECL_OBJC_PROPERTY_IMPL; } void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); if (D->InitStorage.getInt() == FieldDecl::ISK_BitWidthOrNothing && D->InitStorage.getPointer() == nullptr) { Record.push_back(0); } else if (D->InitStorage.getInt() == FieldDecl::ISK_CapturedVLAType) { Record.push_back(D->InitStorage.getInt() + 1); Writer.AddTypeRef( QualType(static_cast(D->InitStorage.getPointer()), 0), Record); } else { Record.push_back(D->InitStorage.getInt() + 1); Writer.AddStmt(static_cast(D->InitStorage.getPointer())); } if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && !D->isModulePrivate() && !D->getBitWidth() && !D->hasInClassInitializer() && !D->hasExtInfo() && !ObjCIvarDecl::classofKind(D->getKind()) && !ObjCAtDefsFieldDecl::classofKind(D->getKind()) && D->getDeclName()) AbbrevToUse = Writer.getDeclFieldAbbrev(); Code = serialization::DECL_FIELD; } void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) { VisitDeclaratorDecl(D); Writer.AddIdentifierRef(D->getGetterId(), Record); Writer.AddIdentifierRef(D->getSetterId(), Record); Code = serialization::DECL_MS_PROPERTY; } void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { VisitValueDecl(D); Record.push_back(D->getChainingSize()); for (const auto *P : D->chain()) Writer.AddDeclRef(P, Record); Code = serialization::DECL_INDIRECTFIELD; } void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VisitRedeclarable(D); VisitDeclaratorDecl(D); Record.push_back(D->getStorageClass()); Record.push_back(D->getTSCSpec()); Record.push_back(D->getInitStyle()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->isARCPseudoStrong()); Record.push_back(D->isConstexpr()); Record.push_back(D->isInitCapture()); Record.push_back(D->isPreviousDeclInSameBlockScope()); Record.push_back(D->getLinkageInternal()); if (D->getInit()) { Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); Writer.AddStmt(D->getInit()); } else { Record.push_back(0); } enum { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization }; if (VarTemplateDecl *TemplD = D->getDescribedVarTemplate()) { Record.push_back(VarTemplate); Writer.AddDeclRef(TemplD, Record); } else if (MemberSpecializationInfo *SpecInfo = D->getMemberSpecializationInfo()) { Record.push_back(StaticDataMemberSpecialization); Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record); Record.push_back(SpecInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record); } else { Record.push_back(VarNotTemplate); } if (!D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() && D->getInitStyle() == VarDecl::CInit && D->getInit() == nullptr && !isa(D) && !isa(D) && !D->isConstexpr() && !D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() && !D->getMemberSpecializationInfo()) AbbrevToUse = Writer.getDeclVarAbbrev(); Code = serialization::DECL_VAR; } void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { VisitVarDecl(D); Code = serialization::DECL_IMPLICIT_PARAM; } void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); Record.push_back(D->isObjCMethodParameter()); Record.push_back(D->getFunctionScopeDepth()); Record.push_back(D->getFunctionScopeIndex()); Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding Record.push_back(D->isKNRPromoted()); Record.push_back(D->hasInheritedDefaultArg()); Record.push_back(D->hasUninstantiatedDefaultArg()); if (D->hasUninstantiatedDefaultArg()) Writer.AddStmt(D->getUninstantiatedDefaultArg()); Code = serialization::DECL_PARM_VAR; assert(!D->isARCPseudoStrong()); // can be true of ImplicitParamDecl // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. if (!D->hasAttrs() && !D->hasExtInfo() && !D->isImplicit() && !D->isUsed(false) && !D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none && !D->isModulePrivate() && D->getStorageClass() == 0 && D->getInitStyle() == VarDecl::CInit && // Can params have anything else? D->getFunctionScopeDepth() == 0 && D->getObjCDeclQualifier() == 0 && !D->isKNRPromoted() && !D->hasInheritedDefaultArg() && D->getInit() == nullptr && !D->hasUninstantiatedDefaultArg()) // No default expr. AbbrevToUse = Writer.getDeclParmVarAbbrev(); // Check things we know are true of *every* PARM_VAR_DECL, which is more than // just us assuming it. assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS"); assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDecl() == nullptr && "PARM_VAR_DECL can't be redecl"); assert(!D->isStaticDataMember() && "PARM_VAR_DECL can't be static data member"); } void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAsmString()); Writer.AddSourceLocation(D->getRParenLoc(), Record); Code = serialization::DECL_FILE_SCOPE_ASM; } void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { VisitDecl(D); Code = serialization::DECL_EMPTY; } void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Writer.AddStmt(D->getBody()); Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record); Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); Record.push_back(D->isVariadic()); Record.push_back(D->blockMissingReturnType()); Record.push_back(D->isConversionFromLambda()); Record.push_back(D->capturesCXXThis()); Record.push_back(D->getNumCaptures()); for (const auto &capture : D->captures()) { Writer.AddDeclRef(capture.getVariable(), Record); unsigned flags = 0; if (capture.isByRef()) flags |= 1; if (capture.isNested()) flags |= 2; if (capture.hasCopyExpr()) flags |= 4; Record.push_back(flags); if (capture.hasCopyExpr()) Writer.AddStmt(capture.getCopyExpr()); } Code = serialization::DECL_BLOCK; } void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) { Record.push_back(CD->getNumParams()); VisitDecl(CD); Record.push_back(CD->getContextParamPosition()); Record.push_back(CD->isNothrow() ? 1 : 0); // Body is stored by VisitCapturedStmt. for (unsigned I = 0; I < CD->getNumParams(); ++I) Writer.AddDeclRef(CD->getParam(I), Record); Code = serialization::DECL_CAPTURED; } void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); Record.push_back(D->getLanguage()); Writer.AddSourceLocation(D->getExternLoc(), Record); Writer.AddSourceLocation(D->getRBraceLoc(), Record); Code = serialization::DECL_LINKAGE_SPEC; } void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getLocStart(), Record); Code = serialization::DECL_LABEL; } void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { VisitRedeclarable(D); VisitNamedDecl(D); Record.push_back(D->isInline()); Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddSourceLocation(D->getRBraceLoc(), Record); if (D->isOriginalNamespace()) Writer.AddDeclRef(D->getAnonymousNamespace(), Record); Code = serialization::DECL_NAMESPACE; if (Writer.hasChain() && !D->isOriginalNamespace() && D->getOriginalNamespace()->isFromASTFile()) { NamespaceDecl *NS = D->getOriginalNamespace(); Writer.AddUpdatedDeclContext(NS); // Make sure all visible decls are written. They will be recorded later. if (StoredDeclsMap *Map = NS->buildLookup()) { for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); D != DEnd; ++D) { DeclContext::lookup_result R = D->second.getLookupResult(); for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) Writer.GetDeclRef(*I); } } } if (Writer.hasChain() && D->isAnonymousNamespace() && D == D->getMostRecentDecl()) { // This is a most recent reopening of the anonymous namespace. If its parent // is in a previous PCH (or is the TU), mark that parent for update, because // the original namespace always points to the latest re-opening of its // anonymous namespace. Decl *Parent = cast( D->getParent()->getRedeclContext()->getPrimaryContext()); if (Parent->isFromASTFile() || isa(Parent)) { Writer.DeclUpdates[Parent].push_back( ASTWriter::DeclUpdate(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, D)); } } } void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { VisitRedeclarable(D); VisitNamedDecl(D); Writer.AddSourceLocation(D->getNamespaceLoc(), Record); Writer.AddSourceLocation(D->getTargetNameLoc(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Writer.AddDeclRef(D->getNamespace(), Record); Code = serialization::DECL_NAMESPACE_ALIAS; } void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record); Writer.AddDeclRef(D->FirstUsingShadow.getPointer(), Record); Record.push_back(D->hasTypename()); Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record); Code = serialization::DECL_USING; } void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitRedeclarable(D); VisitNamedDecl(D); Writer.AddDeclRef(D->getTargetDecl(), Record); Writer.AddDeclRef(D->UsingOrNextShadow, Record); Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record); Code = serialization::DECL_USING_SHADOW; } void ASTDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Writer.AddDeclRef(D->getNominatedNamespace(), Record); Writer.AddDeclRef(dyn_cast(D->getCommonAncestor()), Record); Code = serialization::DECL_USING_DIRECTIVE; } void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { VisitValueDecl(D); Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record); Code = serialization::DECL_UNRESOLVED_USING_VALUE; } void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { VisitTypeDecl(D); Writer.AddSourceLocation(D->getTypenameLoc(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Code = serialization::DECL_UNRESOLVED_USING_TYPENAME; } void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { VisitRecordDecl(D); enum { CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization }; if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) { Record.push_back(CXXRecTemplate); Writer.AddDeclRef(TemplD, Record); } else if (MemberSpecializationInfo *MSInfo = D->getMemberSpecializationInfo()) { Record.push_back(CXXRecMemberSpecialization); Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record); Record.push_back(MSInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record); } else { Record.push_back(CXXRecNotTemplate); } Record.push_back(D->isThisDeclarationADefinition()); if (D->isThisDeclarationADefinition()) Writer.AddCXXDefinitionData(D, Record); // Store (what we currently believe to be) the key function to avoid // deserializing every method so we can compute it. if (D->IsCompleteDefinition) Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record); Code = serialization::DECL_CXX_RECORD; } void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); if (D->isCanonicalDecl()) { Record.push_back(D->size_overridden_methods()); for (CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), E = D->end_overridden_methods(); I != E; ++I) Writer.AddDeclRef(*I, Record); } else { // We only need to record overridden methods once for the canonical decl. Record.push_back(0); } if (D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() && !D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && !D->hasInheritedPrototype() && D->hasWrittenPrototype()) AbbrevToUse = Writer.getDeclCXXMethodAbbrev(); Code = serialization::DECL_CXX_METHOD; } void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { VisitCXXMethodDecl(D); Writer.AddDeclRef(D->getInheritedConstructor(), Record); Record.push_back(D->IsExplicitSpecified); Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers, Record); Code = serialization::DECL_CXX_CONSTRUCTOR; } void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); Writer.AddDeclRef(D->OperatorDelete, Record); Code = serialization::DECL_CXX_DESTRUCTOR; } void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { VisitCXXMethodDecl(D); Record.push_back(D->IsExplicitSpecified); Code = serialization::DECL_CXX_CONVERSION; } void ASTDeclWriter::VisitImportDecl(ImportDecl *D) { VisitDecl(D); Record.push_back(Writer.getSubmoduleID(D->getImportedModule())); ArrayRef IdentifierLocs = D->getIdentifierLocs(); Record.push_back(!IdentifierLocs.empty()); if (IdentifierLocs.empty()) { Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(1); } else { for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I) Writer.AddSourceLocation(IdentifierLocs[I], Record); Record.push_back(IdentifierLocs.size()); } // Note: the number of source locations must always be the last element in // the record. Code = serialization::DECL_IMPORT; } void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); Writer.AddSourceLocation(D->getColonLoc(), Record); Code = serialization::DECL_ACCESS_SPEC; } void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) { // Record the number of friend type template parameter lists here // so as to simplify memory allocation during deserialization. Record.push_back(D->NumTPLists); VisitDecl(D); bool hasFriendDecl = D->Friend.is(); Record.push_back(hasFriendDecl); if (hasFriendDecl) Writer.AddDeclRef(D->getFriendDecl(), Record); else Writer.AddTypeSourceInfo(D->getFriendType(), Record); for (unsigned i = 0; i < D->NumTPLists; ++i) Writer.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i), Record); Writer.AddDeclRef(D->getNextFriend(), Record); Record.push_back(D->UnsupportedFriend); Writer.AddSourceLocation(D->FriendLoc, Record); Code = serialization::DECL_FRIEND; } void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { VisitDecl(D); Record.push_back(D->getNumTemplateParameters()); for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i) Writer.AddTemplateParameterList(D->getTemplateParameterList(i), Record); Record.push_back(D->getFriendDecl() != nullptr); if (D->getFriendDecl()) Writer.AddDeclRef(D->getFriendDecl(), Record); else Writer.AddTypeSourceInfo(D->getFriendType(), Record); Writer.AddSourceLocation(D->getFriendLoc(), Record); Code = serialization::DECL_FRIEND_TEMPLATE; } void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getTemplatedDecl(), Record); Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); } void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { VisitRedeclarable(D); // Emit data to initialize CommonOrPrev before VisitTemplateDecl so that // getCommonPtr() can be used while this is still initializing. if (D->isFirstDecl()) { // This declaration owns the 'common' pointer, so serialize that data now. Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record); if (D->getInstantiatedFromMemberTemplate()) Record.push_back(D->isMemberSpecialization()); } VisitTemplateDecl(D); Record.push_back(D->getIdentifierNamespace()); } void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); if (D->isFirstDecl()) { typedef llvm::FoldingSetVector CTSDSetTy; CTSDSetTy &CTSDSet = D->getSpecializations(); Record.push_back(CTSDSet.size()); for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } typedef llvm::FoldingSetVector CTPSDSetTy; CTPSDSetTy &CTPSDSet = D->getPartialSpecializations(); Record.push_back(CTPSDSet.size()); for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E=CTPSDSet.end(); I!=E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } } Code = serialization::DECL_CLASS_TEMPLATE; } void ASTDeclWriter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { VisitCXXRecordDecl(D); llvm::PointerUnion InstFrom = D->getSpecializedTemplateOrPartial(); if (Decl *InstFromD = InstFrom.dyn_cast()) { Writer.AddDeclRef(InstFromD, Record); } else { Writer.AddDeclRef(InstFrom.get(), Record); Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); } Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); Record.push_back(D->getSpecializationKind()); Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { // When reading, we'll add it to the folding set of the following template. Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); } // Explicit info. Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); if (D->getTypeAsWritten()) { Writer.AddSourceLocation(D->getExternLoc(), Record); Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); } Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION; } void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { VisitClassTemplateSpecializationDecl(D); Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record); // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); Record.push_back(D->isMemberSpecialization()); } Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); if (D->isFirstDecl()) { typedef llvm::FoldingSetVector VTSDSetTy; VTSDSetTy &VTSDSet = D->getSpecializations(); Record.push_back(VTSDSet.size()); for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } typedef llvm::FoldingSetVector VTPSDSetTy; VTPSDSetTy &VTPSDSet = D->getPartialSpecializations(); Record.push_back(VTPSDSet.size()); for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } } Code = serialization::DECL_VAR_TEMPLATE; } void ASTDeclWriter::VisitVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *D) { VisitVarDecl(D); llvm::PointerUnion InstFrom = D->getSpecializedTemplateOrPartial(); if (Decl *InstFromD = InstFrom.dyn_cast()) { Writer.AddDeclRef(InstFromD, Record); } else { Writer.AddDeclRef(InstFrom.get(), Record); Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); } // Explicit info. Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); if (D->getTypeAsWritten()) { Writer.AddSourceLocation(D->getExternLoc(), Record); Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); } Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); Record.push_back(D->getSpecializationKind()); Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { // When reading, we'll add it to the folding set of the following template. Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); } Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION; } void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { VisitVarTemplateSpecializationDecl(D); Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); Writer.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten(), Record); // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); Record.push_back(D->isMemberSpecialization()); } Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; } void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); Writer.AddDeclRef(D->getSpecialization(), Record); Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION; } void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); if (D->isFirstDecl()) { // This FunctionTemplateDecl owns the CommonPtr; write it. // Write the function specialization declarations. Record.push_back(D->getSpecializations().size()); for (llvm::FoldingSetVector::iterator I = D->getSpecializations().begin(), E = D->getSpecializations().end() ; I != E; ++I) { assert(I->Function->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(I->Function, Record); } } Code = serialization::DECL_FUNCTION_TEMPLATE; } void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); Record.push_back(D->wasDeclaredWithTypename()); Record.push_back(D->defaultArgumentWasInherited()); Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record); Code = serialization::DECL_TEMPLATE_TYPE_PARM; } void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // For an expanded parameter pack, record the number of expansion types here // so that it's easier for deserialization to allocate the right amount of // memory. if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); VisitDeclaratorDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); if (D->isExpandedParameterPack()) { for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { Writer.AddTypeRef(D->getExpansionType(I), Record); Writer.AddTypeSourceInfo(D->getExpansionTypeSourceInfo(I), Record); } Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; } else { // Rest of NonTypeTemplateParmDecl. Record.push_back(D->isParameterPack()); Record.push_back(D->getDefaultArgument() != nullptr); if (D->getDefaultArgument()) { Writer.AddStmt(D->getDefaultArgument()); Record.push_back(D->defaultArgumentWasInherited()); } Code = serialization::DECL_NON_TYPE_TEMPLATE_PARM; } } void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // For an expanded parameter pack, record the number of expansion types here // so that it's easier for deserialization to allocate the right amount of // memory. if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTemplateParameters()); VisitTemplateDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); if (D->isExpandedParameterPack()) { for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); I != N; ++I) Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I), Record); Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; } else { // Rest of TemplateTemplateParmDecl. Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); Record.push_back(D->defaultArgumentWasInherited()); Record.push_back(D->isParameterPack()); Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; } } void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); Code = serialization::DECL_TYPE_ALIAS_TEMPLATE; } void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAssertExpr()); Record.push_back(D->isFailed()); Writer.AddStmt(D->getMessage()); Writer.AddSourceLocation(D->getRParenLoc(), Record); Code = serialization::DECL_STATIC_ASSERT; } /// \brief Emit the DeclContext part of a declaration context decl. /// /// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL /// block for this declaration context is stored. May be 0 to indicate /// that there are no declarations stored within this context. /// /// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE /// block for this declaration context is stored. May be 0 to indicate /// that there are no declarations visible from this context. Note /// that this value will not be emitted for non-primary declaration /// contexts. void ASTDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset) { Record.push_back(LexicalOffset); Record.push_back(VisibleOffset); } template void ASTDeclWriter::VisitRedeclarable(Redeclarable *D) { T *First = D->getFirstDecl(); if (First->getMostRecentDecl() != First) { assert(isRedeclarableDeclKind(static_cast(D)->getKind()) && "Not considered redeclarable?"); // There is more than one declaration of this entity, so we will need to // write a redeclaration chain. Writer.AddDeclRef(First, Record); Writer.Redeclarations.insert(First); // Make sure that we serialize both the previous and the most-recent // declarations, which (transitively) ensures that all declarations in the // chain get serialized. (void)Writer.GetDeclRef(D->getPreviousDecl()); (void)Writer.GetDeclRef(First->getMostRecentDecl()); } else { // We use the sentinel value 0 to indicate an only declaration. Record.push_back(0); } } void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { Record.push_back(D->varlist_size()); VisitDecl(D); for (auto *I : D->varlists()) Writer.AddStmt(I); Code = serialization::DECL_OMP_THREADPRIVATE; } //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// void ASTWriter::WriteDeclAbbrevs() { using namespace llvm; BitCodeAbbrev *Abv; // Abbreviation for DECL_FIELD Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc DeclFieldAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_OBJC_IVAR Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth // ObjC Ivar Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc DeclObjCIvarAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_ENUM Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM)); // Redeclarable Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // TypeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref // TagDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind // EnumDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumPositiveBits Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumNegativeBits Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum // DC Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset DeclEnumAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_RECORD Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD)); // Redeclarable Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // TypeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref // TagDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCompleteDefinition Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFreeStanding Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsCompleteDefinitionRequired Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation Abv->Add(BitCodeAbbrevOp(0)); // ExtInfoKind // RecordDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember // DC Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset DeclRecordAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_PARM_VAR Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR)); // Redeclarable Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass Abv->Add(BitCodeAbbrevOp(0)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope Abv->Add(BitCodeAbbrevOp(0)); // Linkage Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsObjCMethodParameter Abv->Add(BitCodeAbbrevOp(0)); // ScopeDepth Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc DeclParmVarAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_TYPEDEF Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF)); // Redeclarable Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUsed Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // TypeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref // TypedefDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc DeclTypedefAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_VAR Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR)); // Redeclarable Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(0)); // TopLevelDeclInObjCContainer Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc DeclVarAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for DECL_CXX_METHOD Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_CXX_METHOD)); // RedeclarableDecl Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(0)); // Invalid Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Implicit Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Used Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Referenced Abv->Add(BitCodeAbbrevOp(0)); // InObjCContainer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Access Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ModulePrivate Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID // NamedDecl Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo // FunctionDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto Abv->Add(BitCodeAbbrevOp(1)); // HasWrittenProto - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // DeletedAsWritten + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Deleted Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Trivial Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind // This Array slurps the rest of the record. Fortunately we want to encode // (nearly) all the remaining (variable number of) fields in the same way. // // This is the function template information if any, then // NumParams and Params[] from FunctionDecl, and // NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl. // // Add an AbbrevOp for 'size then elements' and use it here. Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); DeclCXXMethodAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for EXPR_DECL_REF Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF)); //Stmt //Expr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind //DeclRefExpr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // RefersToEnclosingVariableOrCapture Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location DeclRefExprAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for EXPR_INTEGER_LITERAL Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL)); //Stmt //Expr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind //Integer Literal Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location Abv->Add(BitCodeAbbrevOp(32)); // Bit Width Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value IntegerLiteralAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for EXPR_CHARACTER_LITERAL Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL)); //Stmt //Expr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind //Character Literal Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv); // Abbreviation for EXPR_IMPLICIT_CAST Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::EXPR_IMPLICIT_CAST)); // Stmt // Expr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //TypeDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ValueDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //InstantiationDependent Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind // CastExpr Abv->Add(BitCodeAbbrevOp(0)); // PathSize Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // CastKind // ImplicitCastExpr ExprImplicitCastAbbrev = Stream.EmitAbbrev(Abv); Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextLexicalAbbrev = Stream.EmitAbbrev(Abv); Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(Abv); } /// isRequiredDecl - Check if this is a "required" Decl, which must be seen by /// consumers of the AST. /// /// Such decls will always be deserialized from the AST file, so we would like /// this to be as restrictive as possible. Currently the predicate is driven by /// code generation requirements, if other clients have a different notion of /// what is "required" then we may have to consider an alternate scheme where /// clients can iterate over the top-level decls and get information on them, /// without necessary deserializing them. We could explicitly require such /// clients to use a separate API call to "realize" the decl. This should be /// relatively painless since they would presumably only do it for top-level /// decls. static bool isRequiredDecl(const Decl *D, ASTContext &Context) { // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. // File scoped assembly or obj-c implementation must be seen. ImportDecl is // used by codegen to determine the set of imported modules to search for // inputs for automatic linking. if (isa(D) || isa(D) || isa(D)) return true; return Context.DeclMustBeEmitted(D); } void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) { // Switch case IDs are per Decl. ClearSwitchCaseIDs(); RecordData Record; ASTDeclWriter W(*this, Context, Record); // Determine the ID for this declaration. serialization::DeclID ID; if (D->isFromASTFile()) ID = getDeclID(D); else { serialization::DeclID &IDR = DeclIDs[D]; if (IDR == 0) IDR = NextDeclID++; ID= IDR; } bool isReplacingADecl = ID < FirstDeclID; // If this declaration is also a DeclContext, write blocks for the // declarations that lexically stored inside its context and those // declarations that are visible from its context. These blocks // are written before the declaration itself so that we can put // their offsets into the record for the declaration. uint64_t LexicalOffset = 0; uint64_t VisibleOffset = 0; DeclContext *DC = dyn_cast(D); if (DC) { if (isReplacingADecl) { // It is replacing a decl from a chained PCH; make sure that the // DeclContext is fully loaded. if (DC->hasExternalLexicalStorage()) DC->LoadLexicalDeclsFromExternalStorage(); if (DC->hasExternalVisibleStorage()) Chain->completeVisibleDeclsMap(DC); } LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); } if (isReplacingADecl) { // We're replacing a decl in a previous file. ReplacedDecls.push_back(ReplacedDeclInfo(ID, Stream.GetCurrentBitNo(), D->getLocation())); } else { unsigned Index = ID - FirstDeclID; // Record the offset for this declaration SourceLocation Loc = D->getLocation(); if (DeclOffsets.size() == Index) DeclOffsets.push_back(DeclOffset(Loc, Stream.GetCurrentBitNo())); else if (DeclOffsets.size() < Index) { DeclOffsets.resize(Index+1); DeclOffsets[Index].setLocation(Loc); DeclOffsets[Index].BitOffset = Stream.GetCurrentBitNo(); } SourceManager &SM = Context.getSourceManager(); if (Loc.isValid() && SM.isLocalSourceLocation(Loc)) associateDeclWithFile(D, ID); } // Build and emit a record for this declaration Record.clear(); W.Code = (serialization::DeclCode)0; W.AbbrevToUse = 0; W.Visit(D); if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); if (!W.Code) llvm::report_fatal_error(StringRef("unexpected declaration kind '") + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); // Flush any expressions that were written as part of this declaration. FlushStmts(); // Flush C++ base specifiers, if there are any. FlushCXXBaseSpecifiers(); // Note declarations that should be deserialized eagerly so that we can add // them to a record in the AST file later. if (isRequiredDecl(D, Context)) EagerlyDeserializedDecls.push_back(ID); } void ASTWriter::AddFunctionDefinition(const FunctionDecl *FD, RecordData &Record) { ClearSwitchCaseIDs(); ASTDeclWriter W(*this, FD->getASTContext(), Record); W.AddFunctionDefinition(FD); } Index: vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp =================================================================== --- vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp (revision 278753) +++ vendor/clang/dist/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp (revision 278754) @@ -1,77 +1,77 @@ // RUN: %clang_cc1 -std=c++1y %s -verify const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}} double f; auto with_float = [f(1.0f)] { using T = decltype(f); using T = float; }; auto with_float_2 = [&f(f)] { // ok, refers to outer f using T = decltype(f); using T = double&; }; // Within the lambda-expression's compound-statement, // the identifier in the init-capture hides any declaration // of the same name in scopes enclosing the lambda-expression. void hiding() { char c; (void) [c("foo")] { static_assert(sizeof(c) == sizeof(const char*), ""); }; (void) [c("bar")] () -> decltype(c) { // outer c, not init-capture return "baz"; // expected-error {{cannot initialize}} }; } struct ExplicitCopy { ExplicitCopy(); // expected-note 2{{not viable}} explicit ExplicitCopy(const ExplicitCopy&); }; auto init_kind_1 = [ec(ExplicitCopy())] {}; auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching constructor}} template void init_kind_template() { auto init_kind_1 = [ec(T())] {}; auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}} } template void init_kind_template(); template void init_kind_template(); // expected-note {{instantiation of}} void void_fn(); int overload_fn(); int overload_fn(int); auto bad_init_1 = [a()] {}; // expected-error {{expected expression}} auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}} auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}} auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}} auto bad_init_5 = [a(overload_fn)] {}; // expected-error {{cannot deduce type for lambda capture 'a' from initializer of type ' void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}} template void pack_1<>(); // expected-note {{instantiation of}} // FIXME: Might need lifetime extension for the temporary here. // See DR1695. auto a = [a(4), b = 5, &c = static_cast(0)] { static_assert(sizeof(a) == sizeof(int), ""); static_assert(sizeof(b) == sizeof(int), ""); using T = decltype(c); using T = const int &; }; -auto b = [a{0}] {}; // expected-error {{include }} +auto b = [a{0}] {}; // expected-error {{include }} expected-warning {{will change meaning in a future version of Clang}} struct S { S(); S(S&&); }; template struct remove_reference { typedef T type; }; template struct remove_reference { typedef T type; }; template decltype(auto) move(T &&t) { return static_cast::type&&>(t); } auto s = [s(move(S()))] {}; template T instantiate_test(T t) { [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}} return t; } int instantiate_test_1 = instantiate_test(0); const char *instantiate_test_2 = instantiate_test("foo"); // expected-note {{here}} Index: vendor/clang/dist/test/CodeGenCUDA/llvm-used.cu =================================================================== --- vendor/clang/dist/test/CodeGenCUDA/llvm-used.cu (nonexistent) +++ vendor/clang/dist/test/CodeGenCUDA/llvm-used.cu (revision 278754) @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -fcuda-is-device -triple nvptx64-unknown-unknown | FileCheck %s + + +// Make sure we emit the proper addrspacecast for llvm.used. PR22383 exposed an +// issue where we were generating a bitcast instead of an addrspacecast. + +// CHECK: @llvm.used = appending global [1 x i8*] [i8* addrspacecast (i8 addrspace(1)* bitcast ([0 x i32] addrspace(1)* @a to i8 addrspace(1)*) to i8*)], section "llvm.metadata" +__attribute__((device)) __attribute__((__used__)) int a[] = {}; Index: vendor/clang/dist/test/CodeGenCXX/ctor-dtor-alias.cpp =================================================================== --- vendor/clang/dist/test/CodeGenCXX/ctor-dtor-alias.cpp (revision 278753) +++ vendor/clang/dist/test/CodeGenCXX/ctor-dtor-alias.cpp (revision 278754) @@ -1,234 +1,245 @@ // RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s // RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns > %t // RUN: FileCheck --check-prefix=CHECK1 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK2 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s // RUN: FileCheck --check-prefix=CHECK6 --input-file=%t %s // RUN: %clang_cc1 %s -triple i686-pc-windows-gnu -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck --check-prefix=COFF %s namespace test1 { // Test that we produce the apropriate comdats when creating aliases to // weak_odr constructors and destructors. // CHECK1: @_ZN5test16foobarIvEC1Ev = weak_odr alias void {{.*}} @_ZN5test16foobarIvEC2Ev // CHECK1: @_ZN5test16foobarIvED1Ev = weak_odr alias void (%"struct.test1::foobar"*)* @_ZN5test16foobarIvED2Ev // CHECK1: define weak_odr void @_ZN5test16foobarIvEC2Ev({{.*}} comdat($_ZN5test16foobarIvEC5Ev) // CHECK1: define weak_odr void @_ZN5test16foobarIvED2Ev({{.*}} comdat($_ZN5test16foobarIvED5Ev) // CHECK1: define weak_odr void @_ZN5test16foobarIvED0Ev({{.*}} comdat($_ZN5test16foobarIvED5Ev) // CHECK1-NOT: comdat // COFF doesn't support comdats with arbitrary names (C5/D5). // COFF-NOT: comdat template struct foobar { foobar() {} virtual ~foobar() {} }; template struct foobar; } namespace test2 { // test that when the destrucor is linkonce_odr we just replace every use of // C1 with C2. // CHECK1: define internal void @__cxx_global_var_init() // CHECK1: call void @_ZN5test26foobarIvEC2Ev // CHECK1: define linkonce_odr void @_ZN5test26foobarIvEC2Ev( void g(); template struct foobar { foobar() { g(); } }; foobar x; } namespace test3 { // test that instead of an internal alias we just use the other destructor // directly. // CHECK1: define internal void @__cxx_global_var_init1() // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test312_GLOBAL__N_11AD2Ev // CHECK1: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev( namespace { struct A { ~A() {} }; struct B : public A {}; } B x; } namespace test4 { // Test that we don't produce aliases from B to A. We cannot because we cannot // guarantee that they will be present in every TU. Instead, we just call // A's destructor directly. // CHECK1: define internal void @__cxx_global_var_init2() // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev // CHECK1: define linkonce_odr void @_ZN5test41AD2Ev( // test that we don't do this optimization at -O0 so that the debugger can // see both destructors. // NOOPT: define internal void @__cxx_global_var_init2() // NOOPT: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev // NOOPT: define linkonce_odr void @_ZN5test41BD2Ev struct A { virtual ~A() {} }; struct B : public A{ ~B() {} }; B X; } namespace test5 { // similar to test4, but with an internal B. // CHECK2: define internal void @__cxx_global_var_init3() // CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev // CHECK2: define linkonce_odr void @_ZN5test51AD2Ev( struct A { virtual ~A() {} }; namespace { struct B : public A{ ~B() {} }; } B X; } namespace test6 { // Test that we use ~A directly, even when ~A is not defined. The symbol for // ~B would have been internal and still contain a reference to ~A. struct A { virtual ~A(); }; namespace { struct B : public A { ~B() {} }; } B X; // CHECK3: define internal void @__cxx_global_var_init4() // CHECK3: call i32 @__cxa_atexit({{.*}}@_ZN5test61AD2Ev } namespace test7 { // Test that we don't produce an alias from ~B to ~A (or crash figuring // out if we should). // pr17875. // CHECK3: define void @_ZN5test71BD2Ev template struct A { ~A() {} }; class B : A { ~B(); }; template class A; B::~B() {} } namespace test8 { // Test that we replace ~zed with ~bar which is an alias to ~foo. // CHECK4: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev // CHECK4: define internal void @__cxx_global_var_init5() // CHECK4: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev struct foo { ~foo(); }; foo::~foo() {} struct bar : public foo { ~bar(); }; bar::~bar() {} struct zed : public bar {}; zed foo; } namespace test9 { struct foo { __attribute__((stdcall)) ~foo() { } }; struct bar : public foo {}; void zed() { // Test that we produce a call to bar's destructor. We used to call foo's, but // it has a different calling conversion. // CHECK4: call void @_ZN5test93barD2Ev bar ptr; } } // CHECK5: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}] // r194296 replaced C::~C with B::~B without emitting the later. class A { public: A(int); virtual ~A(); }; template class B : A { public: B() : A(0) { } __attribute__((always_inline)) ~B() { } }; extern template class B; class C : B { }; void fn1() { new C; } namespace test10 { // Test that if a destructor is in a comdat, we don't try to emit is as an // alias to a base class destructor. struct bar { ~bar(); }; bar::~bar() { } } // closing the namespace causes ~bar to be sent to CodeGen namespace test10 { template struct foo : public bar { ~foo(); }; template foo::~foo() {} template class foo; // CHECK5: define weak_odr void @_ZN6test103fooIiED2Ev({{.*}} comdat($_ZN6test103fooIiED5Ev) } namespace test11 { // Test that when we don't have to worry about COMDATs we produce an alias // from complate to base and from base to base class base. struct bar { ~bar(); }; bar::~bar() {} struct foo : public bar { ~foo(); }; foo::~foo() {} // CHECK6: @_ZN6test113fooD2Ev = alias {{.*}} @_ZN6test113barD2Ev // CHECK6: @_ZN6test113fooD1Ev = alias {{.*}} @_ZN6test113fooD2Ev } + +namespace test12 { +template +struct foo { + ~foo() { delete this; } +}; + +template class foo<1>; +// CHECK6: @_ZN6test123fooILi1EED1Ev = weak_odr alias {{.*}} @_ZN6test123fooILi1EED2Ev +// CHECK6: define weak_odr void @_ZN6test123fooILi1EED2Ev({{.*}}) {{.*}} comdat($_ZN6test123fooILi1EED5Ev) +} Index: vendor/clang/dist/test/CodeGenCXX/debug-info-line.cpp =================================================================== --- vendor/clang/dist/test/CodeGenCXX/debug-info-line.cpp (revision 278753) +++ vendor/clang/dist/test/CodeGenCXX/debug-info-line.cpp (revision 278754) @@ -1,187 +1,214 @@ // RUN: %clang_cc1 -gline-tables-only -std=c++11 -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -gline-tables-only -std=c++11 -fexceptions -fcxx-exceptions -S -emit-llvm %s -o - -triple i686-linux-gnu | FileCheck %s // XFAIL: win32 int &src(); int *sink(); extern "C" __complex float complex_src(); extern "C" __complex float *complex_sink(); // CHECK-LABEL: define void f1() { #line 100 * // The store for the assignment should be attributed to the start of the // assignment expression here, regardless of the location of subexpressions. sink() = src(); // CHECK: store {{.*}}, !dbg [[DBG_F1:!.*]] } struct foo { int i; int &j; __complex float k; foo(); }; // CHECK-LABEL: define foo::foo() : #line 200 i // CHECK: store i32 {{.*}} !dbg [[DBG_FOO_VALUE:!.*]] (src()), j // CHECK: store i32* {{.*}} !dbg [[DBG_FOO_REF:!.*]] (src()), k // CHECK: store float {{.*}} !dbg [[DBG_FOO_COMPLEX:!.*]] (complex_src()) { } // CHECK-LABEL: define {{.*}}f2{{.*}} void f2() { #line 300 * // CHECK: store float {{.*}} !dbg [[DBG_F2:!.*]] complex_sink() = complex_src(); } // CHECK-LABEL: define void f3() { #line 400 * // CHECK: store float {{.*}} !dbg [[DBG_F3:!.*]] complex_sink() += complex_src(); } // CHECK-LABEL: define void f4() { #line 500 auto x // CHECK: store {{.*}} !dbg [[DBG_F4:!.*]] = src(); } // CHECK-LABEL: define void f5() { #line 600 auto x // CHECK: store float {{.*}} !dbg [[DBG_F5:!.*]] = complex_src(); } struct agg { int i; }; agg agg_src(); // CHECK-LABEL: define void f6() { agg x; #line 700 x // CHECK: call void @llvm.memcpy{{.*}} !dbg [[DBG_F6:!.*]] = agg_src(); } // CHECK-LABEL: define void f7() { int *src1(); int src2(); #line 800 int x = ( // CHECK: load {{.*}} !dbg [[DBG_F7:!.*]] src1())[src2()]; } // CHECK-LABEL: define void f8() { int src1[1]; int src2(); #line 900 int x = ( // CHECK: load {{.*}} !dbg [[DBG_F8:!.*]] src1)[src2()]; } // CHECK-LABEL: define void f9(int i) { int src1[1][i]; int src2(); #line 1000 auto x = ( // CHECK: getelementptr {{.*}} !dbg [[DBG_F9:!.*]] src1)[src2()]; } inline void *operator new(decltype(sizeof(1)), void *p) noexcept { return p; } // CHECK-LABEL: define void f10() { void *void_src(); ( // CHECK: icmp {{.*}} !dbg [[DBG_F10_ICMP:.*]] // CHECK: store {{.*}} !dbg [[DBG_F10_STORE:!.*]] #line 1100 new (void_src()) int(src())); } // noexcept just to simplify the codegen a bit void fn() noexcept(true); struct bar { bar(); // noexcept(false) to convolute the global dtor ~bar() noexcept(false); }; // global ctor cleanup // CHECK-LABEL: define // CHECK: invoke{{ }} // CHECK: invoke{{ }} // CHECK: to label {{.*}}, !dbg [[DBG_GLBL_CTOR_B:!.*]] // terminate caller // CHECK-LABEL: define // global dtor cleanup // CHECK-LABEL: define // CHECK: invoke{{ }} // CHECK: invoke{{ }} // CHECK: to label {{.*}}, !dbg [[DBG_GLBL_DTOR_B:!.*]] #line 1500 bar b[1] = { // (fn(), // bar())}; // CHECK-LABEL: define __complex double f11() { __complex double f; // CHECK: store {{.*}} !dbg [[DBG_F11:!.*]] #line 1200 return f; } // CHECK-LABEL: define void f12() { int f12_1(); void f12_2(int = f12_1()); // CHECK: call {{(signext )?}}i32 {{.*}} !dbg [[DBG_F12:!.*]] #line 1300 f12_2(); } // CHECK-LABEL: define void f13() { // CHECK: call {{.*}} !dbg [[DBG_F13:!.*]] #define F13_IMPL 1, src() 1, #line 1400 F13_IMPL; } +struct f14 { + f14(int); +}; + +// CHECK-LABEL: define +struct f14_use { +// CHECK: call {{.*}}, !dbg [[DBG_F14_CTOR_CALL:![0-9]*]] +#line 1600 + f14 v + = + 1; + f14_use(); +}; + +f14_use::f14_use() = default; + +// CHECK-LABEL: define + +// CHECK-LABEL: define +int f21_a(int = 0); +void f21_b(int = f21_a()); +void f21() { +// CHECK: call {{.*}}f21_b{{.*}}, !dbg [[DBG_F21:![0-9]*]] +#line 2300 + f21_b(); +} + // CHECK: [[DBG_F1]] = !MDLocation(line: 100, // CHECK: [[DBG_FOO_VALUE]] = !MDLocation(line: 200, // CHECK: [[DBG_FOO_REF]] = !MDLocation(line: 202, // CHECK: [[DBG_FOO_COMPLEX]] = !MDLocation(line: 204, // CHECK: [[DBG_F2]] = !MDLocation(line: 300, // CHECK: [[DBG_F3]] = !MDLocation(line: 400, // CHECK: [[DBG_F4]] = !MDLocation(line: 500, // CHECK: [[DBG_F5]] = !MDLocation(line: 600, // CHECK: [[DBG_F6]] = !MDLocation(line: 700, // CHECK: [[DBG_F7]] = !MDLocation(line: 800, // CHECK: [[DBG_F8]] = !MDLocation(line: 900, // CHECK: [[DBG_F9]] = !MDLocation(line: 1000, // CHECK: [[DBG_F10_ICMP]] = !MDLocation(line: 1100, // CHECK: [[DBG_F10_STORE]] = !MDLocation(line: 1100, // CHECK: [[DBG_GLBL_CTOR_B]] = !MDLocation(line: 1500, // CHECK: [[DBG_GLBL_DTOR_B]] = !MDLocation(line: 1500, // CHECK: [[DBG_F11]] = !MDLocation(line: 1200, // CHECK: [[DBG_F12]] = !MDLocation(line: 1300, // CHECK: [[DBG_F13]] = !MDLocation(line: 1400, Index: vendor/clang/dist/test/PCH/implicitly-deleted.cpp =================================================================== --- vendor/clang/dist/test/PCH/implicitly-deleted.cpp (nonexistent) +++ vendor/clang/dist/test/PCH/implicitly-deleted.cpp (revision 278754) @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++11 -x c++-header %s -emit-pch -o %t.pch +// RUN: %clang_cc1 -std=c++11 -x c++ /dev/null -include-pch %t.pch +class move_only { move_only(const move_only&) = delete; move_only(move_only&&); }; +struct sb { + move_only il; + sb(); + sb(sb &&); +}; + +template T make(); +template void doit(decltype(T(make()))*) { T(make()); } +template void doit(...) { T(make()); } +template void later() { doit(0); } + +void fn1() { + sb x; + later(); +} Property changes on: vendor/clang/dist/test/PCH/implicitly-deleted.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/clang/dist/test/Parser/cxx0x-lambda-expressions.cpp =================================================================== --- vendor/clang/dist/test/Parser/cxx0x-lambda-expressions.cpp (revision 278753) +++ vendor/clang/dist/test/Parser/cxx0x-lambda-expressions.cpp (revision 278754) @@ -1,110 +1,110 @@ // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s enum E { e }; constexpr int id(int n) { return n; } class C { int f() { int foo, bar; []; // expected-error {{expected body of lambda expression}} [+] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} [foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}} [foo,&this] {}; // expected-error {{'this' cannot be captured by reference}} [&this] {}; // expected-error {{'this' cannot be captured by reference}} [&,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} [=,] {}; // expected-error {{expected variable name or 'this' in lambda capture list}} [] {}; [=] (int i) {}; [&] (int) mutable -> void {}; [foo,bar] () { return 3; }; [=,&foo] () {}; [&,foo] () {}; [this] () {}; [] () -> class C { return C(); }; [] () -> enum E { return e; }; [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}} [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}} [](int) -> {}; // PR13652 expected-error {{expected a type}} return 1; } void designator_or_lambda() { typedef int T; const int b = 0; const int c = 1; int d; int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}} int a2[1] = {[b] = 1 }; int a3[1] = {[b,c] = 1 }; // expected-error{{expected ']'}} expected-note {{to match}} int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}} int a5[3] = { []{return 0;}() }; int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}} int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}} int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}} int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}} int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}} int a11[1] = {[id(0)] = 1}; } void delete_lambda(int *p) { delete [] p; delete [] (int*) { new int }; // ok, compound-literal, not lambda delete [] { return new int; } (); // expected-error{{expected expression}} delete [&] { return new int; } (); // ok, lambda } // We support init-captures in C++11 as an extension. int z; void init_capture() { [n(0)] () mutable -> int { return ++n; }; // expected-warning{{extension}} - [n{0}] { return; }; // expected-error {{}} expected-warning{{extension}} + [n{0}] { return; }; // expected-error {{}} expected-warning{{extension}} expected-warning{{will change meaning in a future version}} [n = 0] { return ++n; }; // expected-error {{captured by copy in a non-mutable}} expected-warning{{extension}} [n = {0}] { return; }; // expected-error {{}} expected-warning{{extension}} [a([&b = z]{})](){}; // expected-warning 2{{extension}} int x = 4; auto y = [&r = x, x = x + 1]() -> int { // expected-warning 2{{extension}} r += 2; return x + 2; } (); } void attributes() { [] [[]] {}; // expected-error {{lambda requires '()' before attribute specifier}} [] __attribute__((noreturn)) {}; // expected-error {{lambda requires '()' before attribute specifier}} []() [[]] mutable {}; // expected-error {{expected body of lambda expression}} []() [[]] {}; []() [[]] -> void {}; []() mutable [[]] -> void {}; []() mutable noexcept [[]] -> void {}; // Testing GNU-style attributes on lambdas -- the attribute is specified // before the mutable specifier instead of after (unlike C++11). []() __attribute__((noreturn)) mutable { while(1); }; []() mutable __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}} } }; template void PR22122() { [](int) -> {}; // expected-error {{expected a type}} } template void PR22122(); struct S { template void m (T x =[0); // expected-error{{expected variable name or 'this' in lambda capture list}} } s; struct U { template void m_fn1(T x = 0[0); // expected-error{{expected ']'}} expected-note{{to match this '['}} } *U; Index: vendor/clang/dist/test/Parser/objcxx0x-lambda-expressions.mm =================================================================== --- vendor/clang/dist/test/Parser/objcxx0x-lambda-expressions.mm (revision 278753) +++ vendor/clang/dist/test/Parser/objcxx0x-lambda-expressions.mm (revision 278754) @@ -1,43 +1,43 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -Wno-c++1y-extensions -std=c++11 %s class C { id get(int); void f() { int foo, bar, baz; // fail to parse as a lambda introducer, so we get objc message parsing errors instead [foo,+] {}; // expected-error {{expected expression}} []; // expected-error {{expected body of lambda expression}} [=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}} [&this] {}; // expected-error {{cannot take the address of an rvalue of type 'C *'}} [] {}; [=] (int i) {}; [&] (int) mutable -> void {}; [foo,bar] () { return 3; }; [=,&foo] () {}; [this] () {}; [foo(bar)] () {}; [foo = bar] () {}; - [foo{bar}] () {}; // expected-error {{}} + [foo{bar}] () {}; // expected-error {{}} expected-warning {{will change meaning}} [foo = {bar}] () {}; // expected-error {{}} [foo(bar) baz] () {}; // expected-error {{called object type 'int' is not a function}} [foo(bar), baz] () {}; // ok [foo = bar baz]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}} [get(bar) baz]; // expected-warning {{instance method '-baz'}} [get(bar), baz]; // expected-error {{expected body of lambda}} [foo = bar ++ baz]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}} [foo = bar + baz]; // expected-error {{expected body of lambda}} [foo = { bar, baz }]; // expected-error {{}} expected-error {{expected body of lambda}} [foo = { bar } baz ]; // expected-warning {{receiver type 'int'}} expected-warning {{instance method '-baz'}} [foo = { bar }, baz ]; // expected-error {{}} expected-error {{expected body of lambda}} } }; Index: vendor/clang/dist/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp =================================================================== --- vendor/clang/dist/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (revision 278753) +++ vendor/clang/dist/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (revision 278754) @@ -1,261 +1,262 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s // This must obviously come before the definition of std::initializer_list. void missing_initializerlist() { auto l = {1, 2, 3, 4}; // expected-error {{std::initializer_list was not found}} } namespace std { typedef decltype(sizeof(int)) size_t; // libc++'s implementation template class initializer_list { const _E* __begin_; size_t __size_; initializer_list(const _E* __b, size_t __s) : __begin_(__b), __size_(__s) {} public: typedef _E value_type; typedef const _E& reference; typedef const _E& const_reference; typedef size_t size_type; typedef const _E* iterator; typedef const _E* const_iterator; initializer_list() : __begin_(nullptr), __size_(0) {} size_t size() const {return __size_;} const _E* begin() const {return __begin_;} const _E* end() const {return __begin_ + __size_;} }; } template struct same_type { static const bool value = false; }; template struct same_type { static const bool value = true; }; struct one { char c[1]; }; struct two { char c[2]; }; struct A { int a, b; }; struct B { B(); B(int, int); }; void simple_list() { std::initializer_list il = { 1, 2, 3 }; std::initializer_list dl = { 1.0, 2.0, 3 }; std::initializer_list al = { {1, 2}, {2, 3}, {3, 4} }; std::initializer_list bl = { {1, 2}, {2, 3}, {} }; } void function_call() { void f(std::initializer_list); f({1, 2, 3}); void g(std::initializer_list); g({ {1, 2}, {2, 3}, {} }); } struct C { C(int); }; struct D { D(); operator int(); operator C(); }; void overloaded_call() { one overloaded(std::initializer_list); two overloaded(std::initializer_list); static_assert(sizeof(overloaded({1, 2, 3})) == sizeof(one), "bad overload"); static_assert(sizeof(overloaded({ {1, 2}, {2, 3}, {} })) == sizeof(two), "bad overload"); void ambiguous(std::initializer_list); // expected-note {{candidate}} void ambiguous(std::initializer_list); // expected-note {{candidate}} ambiguous({ {1, 2}, {2, 3}, {3, 4} }); // expected-error {{ambiguous}} one ov2(std::initializer_list); // expected-note {{candidate}} two ov2(std::initializer_list); // expected-note {{candidate}} // Worst sequence to int is identity, whereas to C it's user-defined. static_assert(sizeof(ov2({1, 2, 3})) == sizeof(one), "bad overload"); // But here, user-defined is worst in both cases. ov2({1, 2, D()}); // expected-error {{ambiguous}} } template T deduce(std::initializer_list); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}} template T deduce_ref(const std::initializer_list&); // expected-note {{conflicting types for parameter 'T' ('int' vs. 'double')}} void argument_deduction() { static_assert(same_type::value, "bad deduction"); static_assert(same_type::value, "bad deduction"); deduce({1, 2.0}); // expected-error {{no matching function}} static_assert(same_type::value, "bad deduction"); static_assert(same_type::value, "bad deduction"); deduce_ref({1, 2.0}); // expected-error {{no matching function}} } void auto_deduction() { auto l = {1, 2, 3, 4}; + auto l2 {1, 2, 3, 4}; // expected-warning {{will change meaning in a future version of Clang}} static_assert(same_type>::value, ""); auto bl = {1, 2.0}; // expected-error {{cannot deduce}} for (int i : {1, 2, 3, 4}) {} } void dangle() { new auto{1, 2, 3}; // expected-error {{cannot use list-initialization}} new std::initializer_list{1, 2, 3}; // expected-warning {{at the end of the full-expression}} } struct haslist1 { std::initializer_list il = {1, 2, 3}; // expected-warning{{at the end of the constructor}} std::initializer_list jl{1, 2, 3}; // expected-warning{{at the end of the constructor}} haslist1(); }; haslist1::haslist1() : il{1, 2, 3} // expected-warning{{at the end of the constructor}} {} namespace PR12119 { // Deduction with nested initializer lists. template void f(std::initializer_list); template void g(std::initializer_list>); void foo() { f({0, {1}}); // expected-warning{{braces around scalar initializer}} g({{0, 1}, {2, 3}}); std::initializer_list il = {1, 2}; g({il, {2, 3}}); } } namespace Decay { template void f(std::initializer_list) { T x = 1; // expected-error{{cannot initialize a variable of type 'const char *' with an rvalue of type 'int'}} } void g() { f({"A", "BB", "CCC"}); // expected-note{{in instantiation of function template specialization 'Decay::f' requested here}} auto x = { "A", "BB", "CCC" }; std::initializer_list *il = &x; for( auto s : {"A", "BB", "CCC", "DDD"}) { } } } namespace PR12436 { struct X { template X(std::initializer_list, T); }; X x({}, 17); } namespace rdar11948732 { template struct X {}; struct XCtorInit { XCtorInit(std::initializer_list>); }; void f(X &xi) { XCtorInit xc = { xi, xi }; } } namespace PR14272 { auto x { { 0, 0 } }; // expected-error {{cannot deduce actual type for variable 'x' with type 'auto' from initializer list}} } namespace initlist_of_array { void f(std::initializer_list) {} void f(std::initializer_list) = delete; void h() { f({{1,2},{3,4}}); } } namespace init_list_deduction_failure { void f(); void f(int); template void g(std::initializer_list); // expected-note@-1 {{candidate template ignored: couldn't resolve reference to overloaded function 'f'}} void h() { g({f}); } // expected-error@-1 {{no matching function for call to 'g'}} } namespace deleted_copy { struct X { X(int i) {} X(const X& x) = delete; // expected-note {{here}} void operator=(const X& x) = delete; }; std::initializer_list x{1}; // expected-error {{invokes deleted constructor}} } namespace RefVersusInitList { struct S {}; void f(const S &) = delete; void f(std::initializer_list); void g(S s) { f({S()}); } } namespace PR18013 { int f(); std::initializer_list x = {f}; // expected-error {{cannot initialize an array element of type 'long (*const)()' with an lvalue of type 'int ()': different return type ('long' vs 'int')}} } namespace DR1070 { struct S { S(std::initializer_list); }; S s[3] = { {1, 2, 3}, {4, 5} }; // ok S *p = new S[3] { {1, 2, 3}, {4, 5} }; // ok } namespace ListInitInstantiate { struct A { A(std::initializer_list); A(std::initializer_list); }; struct B : A { B(int); }; template struct X { X(); A a; }; template X::X() : a{B{0}, B{1}} {} X x; int f(const A&); template void g() { int k = f({0}); } template void g(); } Index: vendor/clang/dist/test/SemaCXX/lambda-expressions.cpp =================================================================== --- vendor/clang/dist/test/SemaCXX/lambda-expressions.cpp (revision 278753) +++ vendor/clang/dist/test/SemaCXX/lambda-expressions.cpp (revision 278754) @@ -1,439 +1,448 @@ // RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify -fblocks %s // RUN: %clang_cc1 -std=c++1y -Wno-unused-value -fsyntax-only -verify -fblocks %s namespace std { class type_info; }; namespace ExplicitCapture { class C { int Member; static void Overload(int); void Overload(); virtual C& Overload(float); void ImplicitThisCapture() { [](){(void)Member;}; // expected-error {{'this' cannot be implicitly captured in this context}} [&](){(void)Member;}; [this](){(void)Member;}; [this]{[this]{};}; []{[this]{};};// expected-error {{'this' cannot be implicitly captured in this context}} []{Overload(3);}; []{Overload();}; // expected-error {{'this' cannot be implicitly captured in this context}} []{(void)typeid(Overload());}; []{(void)typeid(Overload(.5f));};// expected-error {{'this' cannot be implicitly captured in this context}} } }; void f() { [this] () {}; // expected-error {{'this' cannot be captured in this context}} } } namespace ReturnDeduction { void test() { [](){ return 1; }; [](){ return 1; }; [](){ return ({return 1; 1;}); }; [](){ return ({return 'c'; 1;}); }; // expected-error {{must match previous return type}} []()->int{ return 'c'; return 1; }; [](){ return 'c'; return 1; }; // expected-error {{must match previous return type}} []() { return; return (void)0; }; [](){ return 1; return 1; }; } } namespace ImplicitCapture { void test() { int a = 0; // expected-note 5 {{declared}} []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}} [&]() { return a; }; [=]() { return a; }; [=]() { int* b = &a; }; // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'}} [=]() { return [&]() { return a; }; }; []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} []() { return [&a] { return a; }; }; // expected-error 2 {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note 2 {{lambda expression begins here}} [=]() { return [&a] { return a; }; }; // const int b = 2; []() { return b; }; union { // expected-note {{declared}} int c; float d; }; d = 3; [=]() { return c; }; // expected-error {{unnamed variable cannot be implicitly captured in a lambda expression}} __block int e; // expected-note 3 {{declared}} [&]() { return e; }; // expected-error {{__block variable 'e' cannot be captured in a lambda expression}} [&e]() { return e; }; // expected-error 2 {{__block variable 'e' cannot be captured in a lambda expression}} int f[10]; // expected-note {{declared}} [&]() { return f[2]; }; (void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \ // expected-note{{lambda expression begins here}} struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}} G g; [=]() { const G* gg = &g; return gg->a; }; [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error {{no matching constructor for initialization of 'G'}} (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const G'}} const int h = a; // expected-note {{declared}} []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} // References can appear in constant expressions if they are initialized by // reference constant expressions. int i; int &ref_i = i; // expected-note {{declared}} [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} static int j; int &ref_j = j; [] { return ref_j; }; // ok } } namespace PR12031 { struct X { template X(const T&); ~X(); }; void f(int i, X x); void g() { const int v = 10; f(v, [](){}); } } namespace Array { int &f(int *p); char &f(...); void g() { int n = -1; [=] { int arr[n]; // VLA } (); const int m = -1; [] { int arr[m]; // expected-error{{negative size}} } (); [&] { int arr[m]; // expected-error{{negative size}} } (); [=] { int arr[m]; // expected-error{{negative size}} } (); [m] { int arr[m]; // expected-error{{negative size}} } (); } } void PR12248() { unsigned int result = 0; auto l = [&]() { ++result; }; } namespace ModifyingCapture { void test() { int n = 0; [=] { n = 1; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}} }; } } namespace VariadicPackExpansion { template using Fst = T; template bool g(Fst ...bools); template bool f(Ts &&...ts) { return g([&ts] { if (!ts) return false; --ts; return true; } () ...); } void h() { int a = 5, b = 2, c = 3; while (f(a, b, c)) { } } struct sink { template sink(Ts &&...) {} }; template void local_class() { sink { [] (Ts t) { struct S : Ts { void f(Ts t) { Ts &that = *this; that = t; } Ts g() { return *this; }; }; S s; s.f(t); return s; } (Ts()).g() ... }; }; struct X {}; struct Y {}; template void local_class(); template void nested(Ts ...ts) { f( // Each expansion of this lambda implicitly captures all of 'ts', because // the inner lambda also expands 'ts'. [&] { return ts + [&] { return f(ts...); } (); } () ... ); } template void nested(int, int, int); template void nested2(Ts ...ts) { // expected-note 2{{here}} // Capture all 'ts', use only one. f([&ts...] { return ts; } ()...); // Capture each 'ts', use it. f([&ts] { return ts; } ()...); // Capture all 'ts', use all of them. f([&ts...] { return (int)f(ts...); } ()); // Capture each 'ts', use all of them. Ill-formed. In more detail: // // We instantiate two lambdas here; the first captures ts$0, the second // captures ts$1. Both of them reference both ts parameters, so both are // ill-formed because ts can't be implicitly captured. // // FIXME: This diagnostic does not explain what's happening. We should // specify which 'ts' we're referring to in its diagnostic name. We should // also say which slice of the pack expansion is being performed in the // instantiation backtrace. f([&ts] { return (int)f(ts...); } ()...); // \ // expected-error 2{{'ts' cannot be implicitly captured}} \ // expected-note 2{{lambda expression begins here}} } template void nested2(int); // ok template void nested2(int, int); // expected-note {{in instantiation of}} } namespace PR13860 { void foo() { auto x = PR13860UndeclaredIdentifier(); // expected-error {{use of undeclared identifier 'PR13860UndeclaredIdentifier'}} auto y = [x]() { }; static_assert(sizeof(y), ""); } } namespace PR13854 { auto l = [](void){}; } namespace PR14518 { auto f = [](void) { return __func__; }; // no-warning } namespace PR16708 { auto L = []() { auto ret = 0; return ret; return 0; }; } namespace TypeDeduction { struct S {}; void f() { const S s {}; S &&t = [&] { return s; } (); #if __cplusplus > 201103L S &&u = [&] () -> auto { return s; } (); #endif } } namespace lambdas_in_NSDMIs { template struct L { T t{}; T t2 = ([](int a) { return [](int b) { return b; };})(t)(t); }; L l; namespace non_template { struct L { int t = 0; int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); }; L l; } } // PR18477: don't try to capture 'this' from an NSDMI encountered while parsing // a lambda. namespace NSDMIs_in_lambdas { template struct S { int a = 0; int b = a; }; void f() { []() { S s; }; } auto x = []{ struct S { int n, m = n; }; }; auto y = [&]{ struct S { int n, m = n; }; }; // expected-error {{non-local lambda expression cannot have a capture-default}} void g() { auto z = [&]{ struct S { int n, m = n; }; }; } } namespace CaptureIncomplete { struct Incomplete; // expected-note 2{{forward decl}} void g(const Incomplete &a); void f(Incomplete &a) { (void) [a] {}; // expected-error {{incomplete}} (void) [&a] {}; (void) [=] { g(a); }; // expected-error {{incomplete}} (void) [&] { f(a); }; } } namespace CaptureAbstract { struct S { virtual void f() = 0; // expected-note {{unimplemented}} int n = 0; }; struct T : S { constexpr T() {} void f(); }; void f() { constexpr T t = T(); S &s = const_cast(t); // FIXME: Once we properly compute odr-use per DR712, this should be // accepted (and should not capture 's'). [=] { return s.n; }; // expected-error {{abstract}} } } namespace PR18128 { auto l = [=]{}; // expected-error {{non-local lambda expression cannot have a capture-default}} struct S { int n; int (*f())[true ? 1 : ([=]{ return n; }(), 0)]; // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} // expected-error@-2 {{invalid use of non-static data member 'n'}} // expected-error@-3 {{a lambda expression may not appear inside of a constant expression}} int g(int k = ([=]{ return n; }(), 0)); // expected-error@-1 {{non-local lambda expression cannot have a capture-default}} // expected-error@-2 {{invalid use of non-static data member 'n'}} int a = [=]{ return n; }(); // ok int b = [=]{ return [=]{ return n; }(); }(); // ok int c = []{ int k = 0; return [=]{ return k; }(); }(); // ok int d = []{ return [=]{ return n; }(); }(); // expected-error {{'this' cannot be implicitly captured in this context}} }; } namespace PR18473 { template void f() { T t(0); (void) [=]{ int n = t; }; // expected-error {{deleted}} } template void f(); struct NoCopy { NoCopy(int); NoCopy(const NoCopy &) = delete; // expected-note {{deleted}} operator int() const; }; template void f(); // expected-note {{instantiation}} } void PR19249() { auto x = [&x]{}; // expected-error {{cannot appear in its own init}} } namespace PR20731 { template void Job(L l); template void Logger(Args &&... args) { auto len = Invalid_Function((args)...); // expected-error@-1 {{use of undeclared identifier 'Invalid_Function'}} Job([len]() {}); } void GetMethod() { Logger(); // expected-note@-1 {{in instantiation of function template specialization 'PR20731::Logger<>' requested here}} } template struct A { T t; // expected-error@-1 {{field has incomplete type 'void'}} }; template void g(F f) { auto a = A{}; // expected-note@-1 {{in instantiation of template class 'PR20731::A' requested here}} auto xf = [a, f]() {}; int x = sizeof(xf); }; void f() { g([] {}); // expected-note-re@-1 {{in instantiation of function template specialization 'PR20731::g<(lambda at {{.*}}>' requested here}} } template struct function { template function(_Fp) { static_assert(sizeof(_Fp) > 0, "Type must be complete."); } }; template void p(T t) { auto l = some_undefined_function(t); // expected-error@-1 {{use of undeclared identifier 'some_undefined_function'}} function(([l]() {})); } void q() { p(0); } // expected-note@-1 {{in instantiation of function template specialization 'PR20731::p' requested here}} } namespace lambda_in_default_mem_init { template void f() { struct S { int n = []{ return 0; }(); }; } template void f(); template void g() { struct S { int n = [](int n){ return n; }(0); }; } template void g(); } namespace error_in_transform_prototype { template void f(T t) { // expected-error@+2 {{type 'int' cannot be used prior to '::' because it has no members}} // expected-error@+1 {{no member named 'ns' in 'error_in_transform_prototype::S'}} auto x = [](typename T::ns::type &k) {}; } class S {}; void foo() { f(5); // expected-note {{requested here}} f(S()); // expected-note {{requested here}} } } + +namespace PR21857 { + template struct fun : Fn { + fun() = default; + using Fn::operator(); + }; + template fun wrap(Fn fn); + auto x = wrap([](){}); +}