diff --git a/.ci/generate_test_report.py b/.ci/generate_test_report.py index 237f45e6f08e0..c44936b19dab9 100644 --- a/.ci/generate_test_report.py +++ b/.ci/generate_test_report.py @@ -18,7 +18,7 @@ def junit_from_xml(xml): class TestReports(unittest.TestCase): def test_title_only(self): - self.assertEqual(_generate_report("Foo", []), ("", None)) + self.assertEqual(_generate_report("Foo", []), ("", "success")) def test_no_tests_in_testsuite(self): self.assertEqual( @@ -336,7 +336,7 @@ def _generate_report(title, junit_objects, size_limit=1024 * 1024, list_failures ) if not tests_run: - return ("", style) + return ("", None) style = "error" if tests_failed else "success" report = [f"# {title}", ""] diff --git a/.ci/metrics/Dockerfile b/.ci/metrics/Dockerfile new file mode 100644 index 0000000000000..80f1c64e3e61b --- /dev/null +++ b/.ci/metrics/Dockerfile @@ -0,0 +1,7 @@ +FROM docker.io/python:3.12 + +COPY requirements.lock.txt ./ +RUN pip3 install --no-cache-dir -r requirements.lock.txt +COPY metrics.py ./ + +CMD ["python3", "metrics.py"] diff --git a/.ci/metrics/metrics.py b/.ci/metrics/metrics.py new file mode 100644 index 0000000000000..deb36bc1689a0 --- /dev/null +++ b/.ci/metrics/metrics.py @@ -0,0 +1,182 @@ +import requests +import time +import os +from dataclasses import dataclass +import sys + +import github +from github import Github +from github import Auth + +GRAFANA_URL = ( + "https://influx-prod-13-prod-us-east-0.grafana.net/api/v1/push/influx/write" +) +GITHUB_PROJECT = "llvm/llvm-project" +WORKFLOWS_TO_TRACK = ["Check code formatting"] +SCRAPE_INTERVAL_SECONDS = 5 * 60 + + +@dataclass +class JobMetrics: + job_name: str + queue_time: int + run_time: int + status: int + created_at_ns: int + workflow_id: int + + +def get_metrics(github_repo: github.Repository, workflows_to_track: dict[str, int]): + """Gets the metrics for specified Github workflows. + + This function takes in a list of workflows to track, and optionally the + workflow ID of the last tracked invocation. It grabs the relevant data + from Github, returning it to the caller. + + Args: + github_repo: A github repo object to use to query the relevant information. + workflows_to_track: A dictionary mapping workflow names to the last + invocation ID where metrics have been collected, or None to collect the + last five results. + + Returns: + Returns a list of JobMetrics objects, containing the relevant metrics about + the workflow. + """ + workflow_runs = iter(github_repo.get_workflow_runs()) + + workflow_metrics = [] + + workflows_to_include = set(workflows_to_track.keys()) + + while len(workflows_to_include) > 0: + workflow_run = next(workflow_runs) + if workflow_run.status != "completed": + continue + + # This workflow was already sampled for this run, or is not tracked at + # all. Ignoring. + if workflow_run.name not in workflows_to_include: + continue + + # There were no new workflow invocations since the previous scrape. + # The API returns a sorted list with the most recent invocations first, + # so we can stop looking for this particular workflow. Continue to grab + # information on the other workflows of interest, if present. + if workflows_to_track[workflow_run.name] == workflow_run.id: + workflows_to_include.remove(workflow_run.name) + continue + + workflow_jobs = workflow_run.jobs() + if workflow_jobs.totalCount == 0: + continue + if workflow_jobs.totalCount > 1: + raise ValueError( + f"Encountered an unexpected number of jobs: {workflow_jobs.totalCount}" + ) + + created_at = workflow_jobs[0].created_at + started_at = workflow_jobs[0].started_at + completed_at = workflow_jobs[0].completed_at + + job_result = int(workflow_jobs[0].conclusion == "success") + + queue_time = started_at - created_at + run_time = completed_at - started_at + + if run_time.seconds == 0: + continue + + if ( + workflows_to_track[workflow_run.name] is None + or workflows_to_track[workflow_run.name] == workflow_run.id + ): + workflows_to_include.remove(workflow_run.name) + if ( + workflows_to_track[workflow_run.name] is not None + and len(workflows_to_include) == 0 + ): + break + + # The timestamp associated with the event is expected by Grafana to be + # in nanoseconds. + created_at_ns = int(created_at.timestamp()) * 10**9 + + workflow_metrics.append( + JobMetrics( + workflow_run.name, + queue_time.seconds, + run_time.seconds, + job_result, + created_at_ns, + workflow_run.id, + ) + ) + + return workflow_metrics + + +def upload_metrics(workflow_metrics, metrics_userid, api_key): + """Upload metrics to Grafana. + + Takes in a list of workflow metrics and then uploads them to Grafana + through a REST request. + + Args: + workflow_metrics: A list of metrics to upload to Grafana. + metrics_userid: The userid to use for the upload. + api_key: The API key to use for the upload. + """ + metrics_batch = [] + for workflow_metric in workflow_metrics: + workflow_formatted_name = workflow_metric.job_name.lower().replace(" ", "_") + metrics_batch.append( + f"{workflow_formatted_name} queue_time={workflow_metric.queue_time},run_time={workflow_metric.run_time},status={workflow_metric.status} {workflow_metric.created_at_ns}" + ) + + request_data = "\n".join(metrics_batch) + response = requests.post( + GRAFANA_URL, + headers={"Content-Type": "text/plain"}, + data=request_data, + auth=(metrics_userid, api_key), + ) + + if response.status_code < 200 or response.status_code >= 300: + print( + f"Failed to submit data to Grafana: {response.status_code}", file=sys.stderr + ) + + +def main(): + # Authenticate with Github + auth = Auth.Token(os.environ["GITHUB_TOKEN"]) + github_object = Github(auth=auth) + github_repo = github_object.get_repo("llvm/llvm-project") + + grafana_api_key = os.environ["GRAFANA_API_KEY"] + grafana_metrics_userid = os.environ["GRAFANA_METRICS_USERID"] + + workflows_to_track = {} + for workflow_to_track in WORKFLOWS_TO_TRACK: + workflows_to_track[workflow_to_track] = None + + # Enter the main loop. Every five minutes we wake up and dump metrics for + # the relevant jobs. + while True: + current_metrics = get_metrics(github_repo, workflows_to_track) + if len(current_metrics) == 0: + print("No metrics found to upload.", file=sys.stderr) + continue + + upload_metrics(current_metrics, grafana_metrics_userid, grafana_api_key) + print(f"Uploaded {len(current_metrics)} metrics", file=sys.stderr) + + for workflow_metric in reversed(current_metrics): + workflows_to_track[workflow_metric.job_name] = workflow_metric.workflow_id + + time.sleep(SCRAPE_INTERVAL_SECONDS) + + +if __name__ == "__main__": + main() diff --git a/.ci/metrics/requirements.lock.txt b/.ci/metrics/requirements.lock.txt new file mode 100644 index 0000000000000..8ab76327e0c82 --- /dev/null +++ b/.ci/metrics/requirements.lock.txt @@ -0,0 +1,335 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --generate-hashes --output-file=./requirements.lock.txt ./requirements.txt +# +certifi==2024.8.30 \ + --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ + --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 + # via requests +cffi==1.17.1 \ + --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \ + --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \ + --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \ + --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \ + --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \ + --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \ + --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \ + --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \ + --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \ + --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \ + --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \ + --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \ + --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \ + --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \ + --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \ + --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \ + --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \ + --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \ + --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \ + --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \ + --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \ + --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \ + --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \ + --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \ + --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \ + --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \ + --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \ + --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \ + --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \ + --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \ + --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \ + --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \ + --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \ + --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \ + --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \ + --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \ + --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \ + --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \ + --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \ + --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \ + --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \ + --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \ + --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \ + --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \ + --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \ + --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \ + --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \ + --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \ + --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ + --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ + --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ + --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ + --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ + --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \ + --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \ + --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \ + --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \ + --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \ + --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \ + --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \ + --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \ + --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \ + --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \ + --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \ + --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \ + --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b + # via + # cryptography + # pynacl +charset-normalizer==3.4.0 \ + --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \ + --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \ + --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \ + --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \ + --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \ + --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \ + --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \ + --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \ + --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \ + --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \ + --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \ + --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \ + --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \ + --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \ + --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \ + --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \ + --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \ + --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \ + --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \ + --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \ + --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \ + --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \ + --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \ + --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \ + --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \ + --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \ + --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \ + --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \ + --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \ + --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \ + --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \ + --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \ + --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \ + --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \ + --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \ + --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \ + --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \ + --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \ + --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \ + --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \ + --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \ + --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \ + --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \ + --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \ + --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \ + --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \ + --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \ + --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \ + --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \ + --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \ + --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \ + --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \ + --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \ + --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \ + --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \ + --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \ + --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \ + --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \ + --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \ + --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \ + --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \ + --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \ + --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \ + --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \ + --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \ + --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \ + --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \ + --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \ + --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \ + --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \ + --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \ + --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \ + --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482 + # via requests +cryptography==43.0.3 \ + --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ + --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ + --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ + --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ + --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ + --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ + --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ + --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ + --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ + --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ + --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ + --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ + --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ + --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ + --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ + --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ + --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ + --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ + --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ + --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ + --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ + --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ + --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ + --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ + --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ + --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ + --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 + # via pyjwt +deprecated==1.2.15 \ + --hash=sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320 \ + --hash=sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d + # via pygithub +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 + # via requests +pycparser==2.22 \ + --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \ + --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc + # via cffi +pygithub==2.5.0 \ + --hash=sha256:b0b635999a658ab8e08720bdd3318893ff20e2275f6446fcf35bf3f44f2c0fd2 \ + --hash=sha256:e1613ac508a9be710920d26eb18b1905ebd9926aa49398e88151c1b526aad3cf + # via -r ./requirements.txt +pyjwt[crypto]==2.10.0 \ + --hash=sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15 \ + --hash=sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c + # via pygithub +pynacl==1.5.0 \ + --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \ + --hash=sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d \ + --hash=sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93 \ + --hash=sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1 \ + --hash=sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92 \ + --hash=sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff \ + --hash=sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba \ + --hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \ + --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ + --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 + # via pygithub +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 + # via pygithub +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 + # via pygithub +urllib3==2.2.3 \ + --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ + --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9 + # via + # pygithub + # requests +wrapt==1.16.0 \ + --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \ + --hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \ + --hash=sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09 \ + --hash=sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e \ + --hash=sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca \ + --hash=sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0 \ + --hash=sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb \ + --hash=sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487 \ + --hash=sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40 \ + --hash=sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c \ + --hash=sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060 \ + --hash=sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202 \ + --hash=sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41 \ + --hash=sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9 \ + --hash=sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b \ + --hash=sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664 \ + --hash=sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d \ + --hash=sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362 \ + --hash=sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00 \ + --hash=sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc \ + --hash=sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1 \ + --hash=sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267 \ + --hash=sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956 \ + --hash=sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966 \ + --hash=sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1 \ + --hash=sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228 \ + --hash=sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72 \ + --hash=sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d \ + --hash=sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292 \ + --hash=sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0 \ + --hash=sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0 \ + --hash=sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36 \ + --hash=sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c \ + --hash=sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5 \ + --hash=sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f \ + --hash=sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73 \ + --hash=sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b \ + --hash=sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2 \ + --hash=sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593 \ + --hash=sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39 \ + --hash=sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389 \ + --hash=sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf \ + --hash=sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf \ + --hash=sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89 \ + --hash=sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c \ + --hash=sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c \ + --hash=sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f \ + --hash=sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440 \ + --hash=sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465 \ + --hash=sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136 \ + --hash=sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b \ + --hash=sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8 \ + --hash=sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3 \ + --hash=sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8 \ + --hash=sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6 \ + --hash=sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e \ + --hash=sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f \ + --hash=sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c \ + --hash=sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e \ + --hash=sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8 \ + --hash=sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2 \ + --hash=sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020 \ + --hash=sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35 \ + --hash=sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d \ + --hash=sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3 \ + --hash=sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537 \ + --hash=sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809 \ + --hash=sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d \ + --hash=sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a \ + --hash=sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4 + # via deprecated diff --git a/.ci/metrics/requirements.txt b/.ci/metrics/requirements.txt new file mode 100644 index 0000000000000..ab5ad7d9e469c --- /dev/null +++ b/.ci/metrics/requirements.txt @@ -0,0 +1 @@ +pygithub==2.5.0 diff --git a/.github/new-issues-labeler.yml b/.github/new-issues-labeler.yml index 860535bbe3083..ee7506c1366ef 100644 --- a/.github/new-issues-labeler.yml +++ b/.github/new-issues-labeler.yml @@ -30,3 +30,9 @@ 'infra:commit-access-request': - '/Request Commit Access/' + +'false-positive': + - '\bfalse[- ]positive\b' + +'false-negative': + - '\bfalse[- ]negative\b' diff --git a/.github/workflows/build-ci-container.yml b/.github/workflows/build-ci-container.yml index 28fc7de2ee065..f037a91f6e5d0 100644 --- a/.github/workflows/build-ci-container.yml +++ b/.github/workflows/build-ci-container.yml @@ -18,44 +18,18 @@ on: - '.github/workflows/containers/github-action-ci/**' jobs: - # TODO(boomanaiden154): Switch this back to a single stage build when we can - # run this on the self-hosted runners and don't have to do it this way to - # avoid timeouts. - build-ci-container-stage1: + build-ci-container: if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + runs-on: depot-ubuntu-22.04-16 + outputs: + container-name: ${{ steps.vars.outputs.container-name }} + container-name-tag: ${{ steps.vars.outputs.container-name-tag }} + container-filename: ${{ steps.vars.outputs.container-filename }} steps: - name: Checkout LLVM uses: actions/checkout@v4 with: sparse-checkout: .github/workflows/containers/github-action-ci/ - - name: Change podman Root Direcotry - run: | - mkdir -p ~/.config/containers - sudo mkdir -p /mnt/podman - sudo chown `whoami`:`whoami` /mnt/podman - cp ./.github/workflows/containers/github-action-ci/storage.conf ~/.config/containers/storage.conf - podman info - - name: Build container stage1 - working-directory: ./.github/workflows/containers/github-action-ci/ - run: | - podman build -t stage1-toolchain --target stage1-toolchain -f stage1.Dockerfile . - - name: Save container image - run: | - podman save stage1-toolchain > stage1-toolchain.tar - - name: Upload container image - uses: actions/upload-artifact@v4 - with: - name: stage1-toolchain - path: stage1-toolchain.tar - retention-days: 1 - build-ci-container-stage2: - if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest - needs: build-ci-container-stage1 - permissions: - packages: write - steps: - name: Write Variables id: vars run: | @@ -63,38 +37,25 @@ jobs: container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/ci-ubuntu-22.04" echo "container-name=$container_name" >> $GITHUB_OUTPUT echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT - - - name: Checkout LLVM - uses: actions/checkout@v4 - with: - sparse-checkout: .github/workflows/containers/github-action-ci/ - - - name: Change podman Root Direcotry + echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT + - name: Build container + working-directory: ./.github/workflows/containers/github-action-ci/ run: | - mkdir -p ~/.config/containers - sudo mkdir -p /mnt/podman - sudo chown `whoami`:`whoami` /mnt/podman - cp ./.github/workflows/containers/github-action-ci/storage.conf ~/.config/containers/storage.conf - podman info + podman build -t ${{ steps.vars.outputs.container-name-tag }} . - # Download the container image into /mnt/podman rather than - # $GITHUB_WORKSPACE to avoid space limitations on the default drive - # and use the permissions setup for /mnt/podman. - - name: Download stage1-toolchain - uses: actions/download-artifact@v4 - with: - name: stage1-toolchain - path: /mnt/podman - - - name: Load stage1-toolchain + # Save the container so we have it in case the push fails. This also + # allows us to separate the push step into a different job so we can + # maintain minimal permissions while building the container. + - name: Save container image run: | - podman load -i /mnt/podman/stage1-toolchain.tar + podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }} - - name: Build Container - working-directory: ./.github/workflows/containers/github-action-ci/ - run: | - podman build -t ${{ steps.vars.outputs.container-name-tag }} -f stage2.Dockerfile . - podman tag ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name }}:latest + - name: Upload container image + uses: actions/upload-artifact@v4 + with: + name: container + path: ${{ steps.vars.outputs.container-filename }} + retention-days: 14 - name: Test Container run: | @@ -102,11 +63,25 @@ jobs: podman run --rm -it $image /usr/bin/bash -x -c 'printf '\''#include \nint main(int argc, char **argv) { std::cout << "Hello\\n"; }'\'' | clang++ -x c++ - && ./a.out | grep Hello' done + push-ci-container: + if: github.event_name == 'push' + needs: + - build-ci-container + permissions: + packages: write + runs-on: ubuntu-24.04 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Download container + uses: actions/download-artifact@v4 + with: + name: container + - name: Push Container - if: github.event_name == 'push' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + podman load -i ${{ needs.build-ci-container.outptus.container-filename }} + podman tag ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name }}:latest podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io - podman push ${{ steps.vars.outputs.container-name-tag }} - podman push ${{ steps.vars.outputs.container-name }}:latest + podman push ${{ needs.build-ci-container.outputs.container-name-tag }} + podman push ${{ needs.build-ci-container.outputs.container-name }}:latest diff --git a/.github/workflows/build-metrics-container.yml b/.github/workflows/build-metrics-container.yml new file mode 100644 index 0000000000000..751ab679411dc --- /dev/null +++ b/.github/workflows/build-metrics-container.yml @@ -0,0 +1,78 @@ +name: Build Metrics Container + +permissions: + contents: read + +on: + push: + branches: + - main + paths: + - .github/workflows/build-metrics-container.yml + - '.ci/metrics/**' + pull_request: + branches: + - main + paths: + - .github/workflows/build-metrics-container.yml + - '.ci/metrics/**' + +jobs: + build-metrics-container: + if: github.repository_owner == 'llvm' + runs-on: ubuntu-latest + outputs: + container-name: ${{ steps.vars.outputs.container-name }} + container-name-tag: ${{ steps.vars.outputs.container-name-tag }} + container-filename: ${{ steps.vars.outputs.container-filename }} + steps: + - name: Checkout LLVM + uses: actions/checkout@v4 + with: + sparse-checkout: .ci/metrics/ + - name: Write Variables + id: vars + run: | + tag=`date +%s` + container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/metrics" + echo "container-name=$container_name" >> $GITHUB_OUTPUT + echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT + echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT + - name: Build Container + working-directory: ./.ci/metrics + run: | + podman build -t ${{ steps.vars.outputs.container-name-tag }} -f Dockerfile . + # Save the container so we have it in case the push fails. This also + # allows us to separate the push step into a different job so we can + # maintain minimal permissions while building the container. + - name: Save Container Image + run: | + podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }} + - name: Upload Container Image + uses: actions/upload-artifact@v4 + with: + name: container + path: ${{ steps.vars.outputs.container-filename }} + retention-days: 14 + + push-metrics-container: + if: github.event_name == 'push' + needs: + - build-metrics-container + permissions: + packages: write + runs-on: ubuntu-24.04 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Download Container + uses: actions/download-artifact@v4 + with: + name: container + - name: Push Container + run: | + podman load -i ${{ needs.build-metrics-container.outputs.container-filename }} + podman tag ${{ needs.build-metrics-container.outputs.container-name-tag }} ${{ needs.build-metrics-container.outputs.container-name }}:latest + podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io + podman push ${{ needs.build-metrics-container.outputs.container-name-tag }} + podman push ${{ needs.build-metrics-container.outputs.container-name }}:latest diff --git a/.github/workflows/commit-access-review.py b/.github/workflows/commit-access-review.py index 8ea9b1fcc2fb0..91d3a61cdcb17 100644 --- a/.github/workflows/commit-access-review.py +++ b/.github/workflows/commit-access-review.py @@ -62,57 +62,9 @@ def __repr__(self): ) -def run_graphql_query( - query: str, variables: dict, token: str, retry: bool = True -) -> dict: - """ - This function submits a graphql query and returns the results as a - dictionary. - """ - s = requests.Session() - retries = requests.adapters.Retry(total=8, backoff_factor=2, status_forcelist=[504]) - s.mount("https://", requests.adapters.HTTPAdapter(max_retries=retries)) - - headers = { - "Authorization": "bearer {}".format(token), - # See - # https://github.blog/2021-11-16-graphql-global-id-migration-update/ - "X-Github-Next-Global-ID": "1", - } - request = s.post( - url="https://api.github.com/graphql", - json={"query": query, "variables": variables}, - headers=headers, - ) - - rate_limit = request.headers.get("X-RateLimit-Remaining") - print(rate_limit) - if rate_limit and int(rate_limit) < 10: - reset_time = int(request.headers["X-RateLimit-Reset"]) - while reset_time - int(time.time()) > 0: - time.sleep(60) - print( - "Waiting until rate limit reset", - reset_time - int(time.time()), - "seconds remaining", - ) - - if request.status_code == 200: - if "data" not in request.json(): - print(request.json()) - sys.exit(1) - return request.json()["data"] - elif retry: - return run_graphql_query(query, variables, token, False) - else: - raise Exception( - "Failed to run graphql query\nquery: {}\nerror: {}".format( - query, request.json() - ) - ) - - -def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str]: +def check_manual_requests( + gh: github.Github, start_date: datetime.datetime +) -> list[str]: """ Return a list of users who have been asked since ``start_date`` if they want to keep their commit access. @@ -137,10 +89,13 @@ def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str """ formatted_start_date = start_date.strftime("%Y-%m-%dT%H:%M:%S") variables = { - "query": f"type:issue created:>{formatted_start_date} org:llvm repo:llvm-project label:infrastructure:commit-access" + "query": f"type:issue created:>{formatted_start_date} org:llvm repo:llvm-project label:infra:commit-access" } - data = run_graphql_query(query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=query, variables=variables + ) + data = res_data["data"] users = [] for issue in data["search"]["nodes"]: users.extend([user[1:] for user in re.findall("@[^ ,\n]+", issue["body"])]) @@ -148,7 +103,7 @@ def check_manual_requests(start_date: datetime.datetime, token: str) -> list[str return users -def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int: +def get_num_commits(gh: github.Github, user: str, start_date: datetime.datetime) -> int: """ Get number of commits that ``user`` has been made since ``start_date`. """ @@ -166,7 +121,10 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int } """ - data = run_graphql_query(user_query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=user_query, variables=variables + ) + data = res_data["data"] variables["user_id"] = data["user"]["id"] query = """ @@ -193,7 +151,10 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int } """ count = 0 - data = run_graphql_query(query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=query, variables=variables + ) + data = res_data["data"] for repo in data["organization"]["teams"]["nodes"][0]["repositories"]["nodes"]: count += int(repo["ref"]["target"]["history"]["totalCount"]) if count >= User.THRESHOLD: @@ -202,7 +163,7 @@ def get_num_commits(user: str, start_date: datetime.datetime, token: str) -> int def is_new_committer_query_repo( - user: str, start_date: datetime.datetime, token: str + gh: github.Github, user: str, start_date: datetime.datetime ) -> bool: """ Determine if ``user`` is a new committer. A new committer can keep their @@ -220,7 +181,10 @@ def is_new_committer_query_repo( } """ - data = run_graphql_query(user_query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=user_query, variables=variables + ) + data = res_data["data"] variables["owner"] = "llvm" variables["user_id"] = data["user"]["id"] variables["start_date"] = start_date.strftime("%Y-%m-%dT%H:%M:%S") @@ -245,7 +209,10 @@ def is_new_committer_query_repo( } """ - data = run_graphql_query(query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=query, variables=variables + ) + data = res_data["data"] repo = data["organization"]["repository"] commits = repo["ref"]["target"]["history"]["nodes"] if len(commits) == 0: @@ -256,18 +223,22 @@ def is_new_committer_query_repo( return True -def is_new_committer(user: str, start_date: datetime.datetime, token: str) -> bool: +def is_new_committer( + gh: github.Github, user: str, start_date: datetime.datetime +) -> bool: """ Wrapper around is_new_commiter_query_repo to handle exceptions. """ try: - return is_new_committer_query_repo(user, start_date, token) + return is_new_committer_query_repo(gh, user, start_date) except: pass return True -def get_review_count(user: str, start_date: datetime.datetime, token: str) -> int: +def get_review_count( + gh: github.Github, user: str, start_date: datetime.datetime +) -> int: """ Return the number of reviews that ``user`` has done since ``start_date``. """ @@ -286,11 +257,14 @@ def get_review_count(user: str, start_date: datetime.datetime, token: str) -> in "query": f"type:pr commenter:{user} -author:{user} merged:>{formatted_start_date} org:llvm", } - data = run_graphql_query(query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=query, variables=variables + ) + data = res_data["data"] return int(data["search"]["issueCount"]) -def count_prs(triage_list: dict, start_date: datetime.datetime, token: str): +def count_prs(gh: github.Github, triage_list: dict, start_date: datetime.datetime): """ Fetch all the merged PRs for the project since ``start_date`` and update ``triage_list`` with the number of PRs merged for each user. @@ -329,7 +303,10 @@ def count_prs(triage_list: dict, start_date: datetime.datetime, token: str): has_next_page = True while has_next_page: print(variables) - data = run_graphql_query(query, variables, token) + res_header, res_data = gh._Github__requester.graphql_query( + query=query, variables=variables + ) + data = res_data["data"] for pr in data["search"]["nodes"]: # Users can be None if the user has been deleted. if not pr["author"]: @@ -365,14 +342,14 @@ def main(): print("Start:", len(triage_list), "triagers") # Step 0 Check if users have requested commit access in the last year. - for user in check_manual_requests(one_year_ago, token): + for user in check_manual_requests(gh, one_year_ago): if user in triage_list: print(user, "requested commit access in the last year.") del triage_list[user] print("After Request Check:", len(triage_list), "triagers") # Step 1 count all PRs authored or merged - count_prs(triage_list, one_year_ago, token) + count_prs(gh, triage_list, one_year_ago) print("After PRs:", len(triage_list), "triagers") @@ -381,7 +358,7 @@ def main(): # Step 2 check for reviews for user in list(triage_list.keys()): - review_count = get_review_count(user, one_year_ago, token) + review_count = get_review_count(gh, user, one_year_ago) triage_list[user].add_reviewed(review_count) print("After Reviews:", len(triage_list), "triagers") @@ -391,7 +368,7 @@ def main(): # Step 3 check for number of commits for user in list(triage_list.keys()): - num_commits = get_num_commits(user, one_year_ago, token) + num_commits = get_num_commits(gh, user, one_year_ago) # Override the total number of commits to not double count commits and # authored PRs. triage_list[user].set_authored(num_commits) @@ -401,7 +378,7 @@ def main(): # Step 4 check for new committers for user in list(triage_list.keys()): print("Checking", user) - if is_new_committer(user, one_year_ago, token): + if is_new_committer(gh, user, one_year_ago): print("Removing new committer: ", user) del triage_list[user] diff --git a/.github/workflows/containers/github-action-ci/Dockerfile b/.github/workflows/containers/github-action-ci/Dockerfile new file mode 100644 index 0000000000000..32a809ee268ea --- /dev/null +++ b/.github/workflows/containers/github-action-ci/Dockerfile @@ -0,0 +1,62 @@ +FROM docker.io/library/ubuntu:22.04 as base +ENV LLVM_SYSROOT=/opt/llvm + +FROM base as stage1-toolchain +ENV LLVM_VERSION=19.1.2 + +RUN apt-get update && \ + apt-get install -y \ + wget \ + gcc \ + g++ \ + cmake \ + ninja-build \ + python3 \ + git \ + curl + +RUN curl -O -L https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-$LLVM_VERSION.tar.gz && tar -xf llvmorg-$LLVM_VERSION.tar.gz + +WORKDIR /llvm-project-llvmorg-$LLVM_VERSION + +# Patch to enable better PGO profile data. +# TODO: Remove this for llvm 20 +ADD https://github.com/llvm/llvm-project/commit/738250989ce516f02f809bdfde474a039c77e81f.patch . + +RUN patch -p1 < 738250989ce516f02f809bdfde474a039c77e81f.patch + +RUN cmake -B ./build -G Ninja ./llvm \ + -C ./clang/cmake/caches/BOLT-PGO.cmake \ + -DBOOTSTRAP_LLVM_ENABLE_LLD=ON \ + -DBOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD=ON \ + -DPGO_INSTRUMENT_LTO=Thin \ + -DLLVM_ENABLE_RUNTIMES="compiler-rt" \ + -DCMAKE_INSTALL_PREFIX="$LLVM_SYSROOT" \ + -DLLVM_ENABLE_PROJECTS="bolt;clang;lld;clang-tools-extra" \ + -DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build" \ + -DCLANG_DEFAULT_LINKER="lld" + +RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C ./build install-distribution + +FROM base + +COPY --from=stage1-toolchain $LLVM_SYSROOT $LLVM_SYSROOT + +# Need to install curl for hendrikmuhs/ccache-action +# Need nodejs for some of the GitHub actions. +# Need perl-modules for clang analyzer tests. +# Need git for SPIRV-Tools tests. +RUN apt-get update && \ + apt-get install -y \ + binutils \ + cmake \ + curl \ + git \ + libstdc++-11-dev \ + ninja-build \ + nodejs \ + perl-modules \ + python3-psutil + +ENV LLVM_SYSROOT=$LLVM_SYSROOT +ENV PATH=${LLVM_SYSROOT}/bin:${PATH} diff --git a/.github/workflows/containers/github-action-ci/bootstrap.patch b/.github/workflows/containers/github-action-ci/bootstrap.patch deleted file mode 100644 index 55631c54a396f..0000000000000 --- a/.github/workflows/containers/github-action-ci/bootstrap.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/clang/cmake/caches/BOLT-PGO.cmake b/clang/cmake/caches/BOLT-PGO.cmake -index 1a04ca9a74e5..d092820e4115 100644 ---- a/clang/cmake/caches/BOLT-PGO.cmake -+++ b/clang/cmake/caches/BOLT-PGO.cmake -@@ -4,6 +4,8 @@ set(CLANG_BOOTSTRAP_TARGETS - stage2-clang-bolt - stage2-distribution - stage2-install-distribution -+ clang -+ lld - CACHE STRING "") - set(BOOTSTRAP_CLANG_BOOTSTRAP_TARGETS - clang-bolt diff --git a/.github/workflows/containers/github-action-ci/stage1.Dockerfile b/.github/workflows/containers/github-action-ci/stage1.Dockerfile deleted file mode 100644 index 3e2c1ab11d58b..0000000000000 --- a/.github/workflows/containers/github-action-ci/stage1.Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -FROM docker.io/library/ubuntu:22.04 as base -ENV LLVM_SYSROOT=/opt/llvm - -FROM base as stage1-toolchain -ENV LLVM_VERSION=19.1.2 - -RUN apt-get update && \ - apt-get install -y \ - wget \ - gcc \ - g++ \ - cmake \ - ninja-build \ - python3 \ - git \ - curl - -RUN curl -O -L https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-$LLVM_VERSION.tar.gz && tar -xf llvmorg-$LLVM_VERSION.tar.gz - -WORKDIR /llvm-project-llvmorg-$LLVM_VERSION - -COPY bootstrap.patch / - -# TODO(boomanaiden154): Remove the bootstrap patch once we unsplit the build -# and no longer need to explicitly build the stage2 dependencies. -RUN cat /bootstrap.patch | patch -p1 - -RUN mkdir build - -RUN cmake -B ./build -G Ninja ./llvm \ - -C ./clang/cmake/caches/BOLT-PGO.cmake \ - -DBOOTSTRAP_LLVM_ENABLE_LLD=ON \ - -DBOOTSTRAP_BOOTSTRAP_LLVM_ENABLE_LLD=ON \ - -DPGO_INSTRUMENT_LTO=Thin \ - -DLLVM_ENABLE_RUNTIMES="compiler-rt" \ - -DCMAKE_INSTALL_PREFIX="$LLVM_SYSROOT" \ - -DLLVM_ENABLE_PROJECTS="bolt;clang;lld;clang-tools-extra" \ - -DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build" \ - -DCLANG_DEFAULT_LINKER="lld" \ - -DBOOTSTRAP_CLANG_PGO_TRAINING_DATA_SOURCE_DIR=/llvm-project-llvmorg-$LLVM_VERSION/llvm - -RUN ninja -C ./build stage2-instrumented-clang stage2-instrumented-lld diff --git a/.github/workflows/containers/github-action-ci/stage2.Dockerfile b/.github/workflows/containers/github-action-ci/stage2.Dockerfile deleted file mode 100644 index 0ca0da87734c4..0000000000000 --- a/.github/workflows/containers/github-action-ci/stage2.Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM docker.io/library/ubuntu:22.04 as base -ENV LLVM_SYSROOT=/opt/llvm - -FROM stage1-toolchain AS stage2-toolchain - -RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C ./build install-distribution && rm -rf ./build - -FROM base - -COPY --from=stage2-toolchain $LLVM_SYSROOT $LLVM_SYSROOT - -# Need to install curl for hendrikmuhs/ccache-action -# Need nodejs for some of the GitHub actions. -# Need perl-modules for clang analyzer tests. -# Need git for SPIRV-Tools tests. -RUN apt-get update && \ - apt-get install -y \ - binutils \ - cmake \ - curl \ - git \ - libstdc++-11-dev \ - ninja-build \ - nodejs \ - perl-modules \ - python3-psutil - -ENV LLVM_SYSROOT=$LLVM_SYSROOT -ENV PATH=${LLVM_SYSROOT}/bin:${PATH} diff --git a/.github/workflows/containers/github-action-ci/storage.conf b/.github/workflows/containers/github-action-ci/storage.conf deleted file mode 100644 index 60f295ff1e969..0000000000000 --- a/.github/workflows/containers/github-action-ci/storage.conf +++ /dev/null @@ -1,4 +0,0 @@ -[storage] - driver = "overlay" - runroot = "/mnt/podman/container" - graphroot = "/mnt/podman/image" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 54f82bd4e4c0b..3b9fca21d63cf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -112,58 +112,87 @@ jobs: sudo apt-get update # swig and graphviz are lldb specific dependencies sudo apt-get install -y cmake ninja-build swig graphviz libhwloc-dev + - name: Setup output folder + run: mkdir built-docs - name: Build LLVM docs if: steps.docs-changed-subprojects.outputs.llvm_any_changed == 'true' run: | cmake -B llvm-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C llvm-build docs-llvm-html docs-llvm-man + mkdir built-docs/llvm + cp -r llvm-build/docs/* built-docs/llvm/ - name: Build Clang docs if: steps.docs-changed-subprojects.outputs.clang_any_changed == 'true' run: | cmake -B clang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C clang-build docs-clang-html docs-clang-man + mkdir built-docs/clang + cp -r clang-build/docs/* built-docs/clang/ - name: Build clang-tools-extra docs if: steps.docs-changed-subprojects.outputs.clang-tools-extra_any_changed == 'true' run: | cmake -B clang-tools-extra-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C clang-tools-extra-build docs-clang-tools-html docs-clang-tools-man + mkdir built-docs/clang-tools-extra + cp -r clang-tools-extra-build/docs/* built-docs/clang-tools-extra/ - name: Build LLDB docs if: steps.docs-changed-subprojects.outputs.lldb_any_changed == 'true' run: | cmake -B lldb-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C lldb-build docs-lldb-html docs-lldb-man + mkdir built-docs/lldb + cp -r lldb-build/docs/* built-docs/lldb/ - name: Build libunwind docs if: steps.docs-changed-subprojects.outputs.libunwind_any_changed == 'true' run: | cmake -B libunwind-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes TZ=UTC ninja -C libunwind-build docs-libunwind-html + mkdir built-docs/libunwind + cp -r libunwind-build/libunwind/docs/* built-docs/libunwind - name: Build libcxx docs if: steps.docs-changed-subprojects.outputs.libcxx_any_changed == 'true' run: | cmake -B libcxx-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libcxxabi;libcxx;libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes TZ=UTC ninja -C libcxx-build docs-libcxx-html + mkdir built-docs/libcxx + cp -r libcxx-build/libcxx/docs/* built-docs/libcxx/ - name: Build libc docs if: steps.docs-changed-subprojects.outputs.libc_any_changed == 'true' run: | cmake -B libc-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libc" -DLLVM_ENABLE_SPHINX=ON ./runtimes TZ=UTC ninja -C libc-build docs-libc-html + mkdir built-docs/libc + cp -r libc-build/libc/docs/* built-docs/libc/ - name: Build LLD docs if: steps.docs-changed-subprojects.outputs.lld_any_changed == 'true' run: | cmake -B lld-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="lld" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C lld-build docs-lld-html + mkdir built-docs/lld + cp -r lld-build/docs/* built-docs/lld/ - name: Build OpenMP docs if: steps.docs-changed-subprojects.outputs.openmp_any_changed == 'true' run: | cmake -B openmp-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;openmp" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C openmp-build docs-openmp-html + mkdir built-docs/openmp + cp -r openmp-build/docs/* built-docs/openmp/ - name: Build Polly docs if: steps.docs-changed-subprojects.outputs.polly_any_changed == 'true' run: | cmake -B polly-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="polly" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C polly-build docs-polly-html docs-polly-man + mkdir built-docs/polly + cp -r polly-build/docs/* built-docs/polly/ - name: Build Flang docs if: steps.docs-changed-subprojects.outputs.flang_any_changed == 'true' run: | cmake -B flang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;mlir;flang" -DLLVM_ENABLE_SPHINX=ON ./llvm TZ=UTC ninja -C flang-build docs-flang-html + mkdir built-docs/flang + cp -r flang-build/docs/* built-docs/flang/ + - name: Upload docs + uses: actions/upload-artifact@v4 + with: + name: docs-output + path: built-docs/ diff --git a/.github/workflows/libc-fullbuild-tests.yml b/.github/workflows/libc-fullbuild-tests.yml new file mode 100644 index 0000000000000..58e15ce29546e --- /dev/null +++ b/.github/workflows/libc-fullbuild-tests.yml @@ -0,0 +1,89 @@ +# This workflow is for pre-commit testing of the LLVM-libc project. +name: LLVM-libc Pre-commit Fullbuild Tests +permissions: + contents: read +on: + pull_request: + branches: [ "main" ] + paths: + - 'libc/**' + - '.github/workflows/libc-fullbuild-tests.yml' + +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: + - c_compiler: clang + cpp_compiler: clang++ + # TODO: add back gcc build when it is fixed + # - c_compiler: gcc + # cpp_compiler: g++ + steps: + - uses: actions/checkout@v4 + + # Libc's build is relatively small comparing with other components of LLVM. + # A fresh fullbuild takes about 190MiB of uncompressed disk space, which can + # be compressed into ~40MiB. Limiting the cache size to 1G should be enough. + # Prefer sccache as it is more modern. + # Do not use direct GHAC access even though it is supported by sccache. GHAC rejects + # frequent small object writes. + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + max-size: 1G + key: libc_fullbuild_${{ matrix.c_compiler }} + variant: sccache + + # Notice: + # - MPFR is required by some of the mathlib tests. + # - Debian has a multilib setup, so we need to symlink the asm directory. + # For more information, see https://wiki.debian.org/Multiarch/LibraryPathOverview + - name: Prepare dependencies (Ubuntu) + run: | + sudo apt-get update + sudo apt-get install -y libmpfr-dev libgmp-dev libmpc-dev ninja-build linux-libc-dev + sudo ln -sf /usr/include/$(uname -p)-linux-gnu/asm /usr/include/asm + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + echo "build-install-dir=${{ github.workspace }}/install" >> "$GITHUB_OUTPUT" + + # Configure libc fullbuild with scudo. + # Use MinSizeRel to reduce the size of the build. + - name: Configure CMake + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=MinSizeRel + -DCMAKE_C_COMPILER_LAUNCHER=sccache + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.build-install-dir }} + -DLLVM_ENABLE_RUNTIMES="libc;compiler-rt" + -DLLVM_LIBC_FULL_BUILD=ON + -DLLVM_LIBC_INCLUDE_SCUDO=ON + -DCOMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC=ON + -DCOMPILER_RT_BUILD_GWP_ASAN=OFF + -DCOMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED=OFF + -G Ninja + -S ${{ github.workspace }}/runtimes + + - name: Build + run: > + cmake + --build ${{ steps.strings.outputs.build-output-dir }} + --parallel + --target install + + - name: Test + run: > + cmake + --build ${{ steps.strings.outputs.build-output-dir }} + --parallel + --target check-libc diff --git a/.github/workflows/libc-overlay-tests.yml b/.github/workflows/libc-overlay-tests.yml new file mode 100644 index 0000000000000..8b59d76aed4a8 --- /dev/null +++ b/.github/workflows/libc-overlay-tests.yml @@ -0,0 +1,106 @@ +# This workflow is for pre-commit testing of the LLVM-libc project. +name: LLVM-libc Pre-commit Overlay Tests +permissions: + contents: read +on: + pull_request: + branches: [ "main" ] + paths: + - 'libc/**' + - '.github/workflows/libc-overlay-tests.yml' + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. + fail-fast: false + matrix: + include: + # TODO: add linux gcc when it is fixed + - os: ubuntu-24.04 + compiler: + c_compiler: clang + cpp_compiler: clang++ + - os: windows-2022 + compiler: + c_compiler: clang-cl + cpp_compiler: clang-cl + - os: macos-14 + compiler: + c_compiler: clang + cpp_compiler: clang++ + + steps: + - uses: actions/checkout@v4 + + # Libc's build is relatively small comparing with other components of LLVM. + # A fresh linux overlay takes about 180MiB of uncompressed disk space, which can + # be compressed into ~40MiB. MacOS and Windows overlay builds are less than 10MiB + # after compression. Limiting the cache size to 1G should be enough. + # Prefer sccache as it is modern and it has a guarantee to work with MSVC. + # Do not use direct GHAC access even though it is supported by sccache. GHAC rejects + # frequent small object writes. + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1 + with: + max-size: 1G + key: libc_overlay_build_${{ matrix.os }}_${{ matrix.compiler.c_compiler }} + variant: sccache + + # MPFR is required by some of the mathlib tests. + - name: Prepare dependencies (Ubuntu) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libmpfr-dev libgmp-dev libmpc-dev ninja-build + + # Chocolatey is shipped with Windows runners. Windows Server 2025 recommends WinGet. + # Consider migrating to WinGet when Windows Server 2025 is available. + - name: Prepare dependencies (Windows) + if: runner.os == 'Windows' + run: | + choco install ninja + + - name: Prepare dependencies (macOS) + if: runner.os == 'macOS' + run: | + brew install ninja + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + # Use MinSizeRel to reduce the size of the build. + # Notice that CMP0141=NEW and MSVC_DEBUG_INFORMATION_FORMAT=Embedded are required + # by the sccache tool. + - name: Configure CMake + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.compiler.c_compiler }} + -DCMAKE_BUILD_TYPE=MinSizeRel + -DCMAKE_C_COMPILER_LAUNCHER=sccache + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + -DCMAKE_POLICY_DEFAULT_CMP0141=NEW + -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded + -DLLVM_ENABLE_RUNTIMES=libc + -G Ninja + -S ${{ github.workspace }}/runtimes + + - name: Build + run: > + cmake + --build ${{ steps.strings.outputs.build-output-dir }} + --parallel + --config MinSizeRel + --target libc + + - name: Test + run: > + cmake + --build ${{ steps.strings.outputs.build-output-dir }} + --parallel + --target check-libc diff --git a/.github/workflows/libcxx-restart-preempted-jobs.yaml b/.github/workflows/libcxx-restart-preempted-jobs.yaml index 21879ce19c27c..82d84c01c92af 100644 --- a/.github/workflows/libcxx-restart-preempted-jobs.yaml +++ b/.github/workflows/libcxx-restart-preempted-jobs.yaml @@ -130,3 +130,91 @@ jobs: run_id: context.payload.workflow_run.id }) await create_check_run('success', 'Restarted workflow run due to preempted job') + + restart-test: + if: github.repository_owner == 'llvm' && (github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'cancelled') && github.event.actor.login == 'ldionne' # TESTING ONLY + name: "Restart Job (test)" + permissions: + statuses: read + checks: write + actions: write + runs-on: ubuntu-latest + steps: + - name: "Restart Job (test)" + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 + with: + script: | + const FAILURE_REGEX = /Process completed with exit code 1./ + const PREEMPTION_REGEX = /(The runner has received a shutdown signal)|(The operation was canceled)/ + + function log(msg) { + core.notice(msg) + } + + const wf_run = context.payload.workflow_run + log(`Running on "${wf_run.display_title}" by @${wf_run.actor.login} (event: ${wf_run.event})\nWorkflow run URL: ${wf_run.html_url}`) + + log('Listing check runs for suite') + const check_suites = await github.rest.checks.listForSuite({ + owner: context.repo.owner, + repo: context.repo.repo, + check_suite_id: context.payload.workflow_run.check_suite_id, + per_page: 100 // FIXME: We don't have 100 check runs yet, but we should handle this better. + }) + + preemptions = []; + legitimate_failures = []; + for (check_run of check_suites.data.check_runs) { + log(`Checking check run: ${check_run.id}`); + if (check_run.status != 'completed') { + log('Check run was not completed. Skipping.'); + continue; + } + + if (check_run.conclusion != 'failure' && check_run.conclusion != 'cancelled') { + log(`Check run had conclusion: ${check_run.conclusion}. Skipping.`); + continue; + } + + annotations = await github.rest.checks.listAnnotations({ + owner: context.repo.owner, + repo: context.repo.repo, + check_run_id: check_run.id + }) + + preemption_annotation = annotations.data.find(function(annotation) { + return annotation.annotation_level == 'failure' && + annotation.message.match(PREEMPTION_REGEX) != null; + }); + if (preemption_annotation != null) { + log(`Found preemption message: ${preemption_annotation.message}`); + preemptions.push(check_run); + break; + } + + failure_annotation = annotations.data.find(function(annotation) { + return annotation.annotation_level == 'failure' && + annotation.message.match(FAILURE_REGEX) != null; + }); + if (failure_annotation != null) { + log(`Found legitimate failure annotation: ${failure_annotation.message}`); + legitimate_failures.push(check_run); + break; + } + } + + if (preemptions) { + log('Found some preempted jobs'); + if (legitimate_failures) { + log('Also found some legitimate failures, so not restarting the workflow.'); + } else { + log('Did not find any legitimate failures. Restarting workflow.'); + await github.rest.actions.reRunWorkflowFailedJobs({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id + }) + } + } else { + log('Did not find any preempted jobs. Not restarting the workflow.'); + } diff --git a/.gitignore b/.gitignore index d558f17a7eec3..08457aba4869e 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,8 @@ autoconf/autom4te.cache # VS2017 and VSCode config files. .vscode .vs +#zed config files +.zed # pythonenv for github Codespaces pythonenv* # clangd index. (".clangd" is a config file now, thus trailing slash) diff --git a/bolt/CODE_OWNERS.TXT b/bolt/Maintainers.txt similarity index 100% rename from bolt/CODE_OWNERS.TXT rename to bolt/Maintainers.txt diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index c9b0e103ed514..115e59ca0697e 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -28,6 +28,7 @@ #include "llvm/ADT/iterator.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -276,11 +277,10 @@ class BinaryContext { void deregisterSectionName(const BinarySection &Section); public: - static Expected> - createBinaryContext(Triple TheTriple, StringRef InputFileName, - SubtargetFeatures *Features, bool IsPIC, - std::unique_ptr DwCtx, - JournalingStreams Logger); + static Expected> createBinaryContext( + Triple TheTriple, std::shared_ptr SSP, + StringRef InputFileName, SubtargetFeatures *Features, bool IsPIC, + std::unique_ptr DwCtx, JournalingStreams Logger); /// Superset of compiler units that will contain overwritten code that needs /// new debug info. In a few cases, functions may end up not being @@ -372,6 +372,7 @@ class BinaryContext { bool hasSymbolsWithFileName() const { return HasSymbolsWithFileName; } void setHasSymbolsWithFileName(bool Value) { HasSymbolsWithFileName = Value; } + std::shared_ptr getSymbolStringPool() { return SSP; } /// Return true if relocations against symbol with a given name /// must be created. bool forceSymbolRelocations(StringRef SymbolName) const; @@ -631,6 +632,8 @@ class BinaryContext { std::unique_ptr TheTriple; + std::shared_ptr SSP; + const Target *TheTarget; std::string TripleName; @@ -807,8 +810,10 @@ class BinaryContext { BinaryContext(std::unique_ptr Ctx, std::unique_ptr DwCtx, - std::unique_ptr TheTriple, const Target *TheTarget, - std::string TripleName, std::unique_ptr MCE, + std::unique_ptr TheTriple, + std::shared_ptr SSP, + const Target *TheTarget, std::string TripleName, + std::unique_ptr MCE, std::unique_ptr MOFI, std::unique_ptr AsmInfo, std::unique_ptr MII, diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index 2880bfd03be78..320623cfa15af 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -170,6 +170,9 @@ class DataAggregator : public DataReader { std::string BuildIDBinaryName; /// Memory map info for a single file as recorded in perf.data + /// When a binary has multiple text segments, the Size is computed as the + /// difference of the last address of these segments from the BaseAddress. + /// The base addresses of all text segments must be the same. struct MMapInfo { uint64_t BaseAddress{0}; /// Base address of the mapped binary. uint64_t MMapAddress{0}; /// Address of the executable segment. @@ -493,6 +496,11 @@ class DataAggregator : public DataReader { /// and return a file name matching a given \p FileBuildID. std::optional getFileNameForBuildID(StringRef FileBuildID); + /// Get a constant reference to the parsed binary mmap entries. + const std::unordered_map &getBinaryMMapInfo() { + return BinaryMMapInfo; + } + friend class YAMLProfileWriter; }; } // namespace bolt diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index a808ece12da19..ac96b836ed579 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -123,6 +123,7 @@ void BinaryContext::logBOLTErrorsAndQuitOnFatal(Error E) { BinaryContext::BinaryContext(std::unique_ptr Ctx, std::unique_ptr DwCtx, std::unique_ptr TheTriple, + std::shared_ptr SSP, const Target *TheTarget, std::string TripleName, std::unique_ptr MCE, std::unique_ptr MOFI, @@ -136,12 +137,12 @@ BinaryContext::BinaryContext(std::unique_ptr Ctx, std::unique_ptr DisAsm, JournalingStreams Logger) : Ctx(std::move(Ctx)), DwCtx(std::move(DwCtx)), - TheTriple(std::move(TheTriple)), TheTarget(TheTarget), - TripleName(TripleName), MCE(std::move(MCE)), MOFI(std::move(MOFI)), - AsmInfo(std::move(AsmInfo)), MII(std::move(MII)), STI(std::move(STI)), - InstPrinter(std::move(InstPrinter)), MIA(std::move(MIA)), - MIB(std::move(MIB)), MRI(std::move(MRI)), DisAsm(std::move(DisAsm)), - Logger(Logger), InitialDynoStats(isAArch64()) { + TheTriple(std::move(TheTriple)), SSP(std::move(SSP)), + TheTarget(TheTarget), TripleName(TripleName), MCE(std::move(MCE)), + MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)), MII(std::move(MII)), + STI(std::move(STI)), InstPrinter(std::move(InstPrinter)), + MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)), + DisAsm(std::move(DisAsm)), Logger(Logger), InitialDynoStats(isAArch64()) { RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86; PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize; } @@ -159,8 +160,9 @@ BinaryContext::~BinaryContext() { /// Create BinaryContext for a given architecture \p ArchName and /// triple \p TripleName. Expected> BinaryContext::createBinaryContext( - Triple TheTriple, StringRef InputFileName, SubtargetFeatures *Features, - bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger) { + Triple TheTriple, std::shared_ptr SSP, + StringRef InputFileName, SubtargetFeatures *Features, bool IsPIC, + std::unique_ptr DwCtx, JournalingStreams Logger) { StringRef ArchName = ""; std::string FeaturesStr = ""; switch (TheTriple.getArch()) { @@ -283,8 +285,8 @@ Expected> BinaryContext::createBinaryContext( auto BC = std::make_unique( std::move(Ctx), std::move(DwCtx), std::make_unique(TheTriple), - TheTarget, std::string(TripleName), std::move(MCE), std::move(MOFI), - std::move(AsmInfo), std::move(MII), std::move(STI), + std::move(SSP), TheTarget, std::string(TripleName), std::move(MCE), + std::move(MOFI), std::move(AsmInfo), std::move(MII), std::move(STI), std::move(InstructionPrinter), std::move(MIA), nullptr, std::move(MRI), std::move(DisAsm), Logger); diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp index 640b29ec36d5c..280c7c505eeda 100644 --- a/bolt/lib/Core/DebugNames.cpp +++ b/bolt/lib/Core/DebugNames.cpp @@ -161,6 +161,7 @@ bool static canProcess(const DWARFUnit &Unit, const DIE &Die, case dwarf::DW_TAG_structure_type: case dwarf::DW_TAG_typedef: case dwarf::DW_TAG_unspecified_type: + case dwarf::DW_TAG_union_type: if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_name)) return true; return false; diff --git a/bolt/lib/Passes/VeneerElimination.cpp b/bolt/lib/Passes/VeneerElimination.cpp index b386b2756a2b8..99d0ffeca8cc2 100644 --- a/bolt/lib/Passes/VeneerElimination.cpp +++ b/bolt/lib/Passes/VeneerElimination.cpp @@ -46,16 +46,17 @@ Error VeneerElimination::runOnFunctions(BinaryContext &BC) { if (BF.isIgnored()) continue; + MCInst &FirstInstruction = *(BF.begin()->begin()); const MCSymbol *VeneerTargetSymbol = 0; uint64_t TargetAddress; - if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) { + if (BC.MIB->isTailCall(FirstInstruction)) { + VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction); + } else if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) { if (BinaryFunction *TargetBF = BC.getBinaryFunctionAtAddress(TargetAddress)) VeneerTargetSymbol = TargetBF->getSymbol(); - } else { - MCInst &FirstInstruction = *(BF.begin()->begin()); - if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer")) - VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1); + } else if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer")) { + VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1); } if (!VeneerTargetSymbol) diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 697cac9fbcaa0..2b02086e3e0c9 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -95,6 +95,12 @@ cl::opt ReadPreAggregated( "pa", cl::desc("skip perf and read data from a pre-aggregated file format"), cl::cat(AggregatorCategory)); +cl::opt + ReadPerfEvents("perf-script-events", + cl::desc("skip perf event collection by supplying a " + "perf-script output in a textual format"), + cl::ReallyHidden, cl::init(""), cl::cat(AggregatorCategory)); + static cl::opt TimeAggregator("time-aggr", cl::desc("time BOLT aggregator"), @@ -167,8 +173,9 @@ void DataAggregator::findPerfExecutable() { void DataAggregator::start() { outs() << "PERF2BOLT: Starting data aggregation job for " << Filename << "\n"; - // Don't launch perf for pre-aggregated files - if (opts::ReadPreAggregated) + // Don't launch perf for pre-aggregated files or when perf input is specified + // by the user. + if (opts::ReadPreAggregated || !opts::ReadPerfEvents.empty()) return; findPerfExecutable(); @@ -464,6 +471,13 @@ void DataAggregator::filterBinaryMMapInfo() { int DataAggregator::prepareToParse(StringRef Name, PerfProcessInfo &Process, PerfProcessErrorCallbackTy Callback) { + if (!opts::ReadPerfEvents.empty()) { + outs() << "PERF2BOLT: using pre-processed perf events for '" << Name + << "' (perf-script-events)\n"; + ParsingBuf = opts::ReadPerfEvents; + return 0; + } + std::string Error; outs() << "PERF2BOLT: waiting for perf " << Name << " collection to finish...\n"; @@ -2056,15 +2070,6 @@ std::error_code DataAggregator::parseMMapEvents() { if (FileMMapInfo.first == "(deleted)") continue; - // Consider only the first mapping of the file for any given PID - auto Range = GlobalMMapInfo.equal_range(FileMMapInfo.first); - bool PIDExists = llvm::any_of(make_range(Range), [&](const auto &MI) { - return MI.second.PID == FileMMapInfo.second.PID; - }); - - if (PIDExists) - continue; - GlobalMMapInfo.insert(FileMMapInfo); } @@ -2116,12 +2121,22 @@ std::error_code DataAggregator::parseMMapEvents() { << " using file offset 0x" << Twine::utohexstr(MMapInfo.Offset) << ". Ignoring profile data for this mapping\n"; continue; - } else { - MMapInfo.BaseAddress = *BaseAddress; } + MMapInfo.BaseAddress = *BaseAddress; } - BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo)); + // Try to add MMapInfo to the map and update its size. Large binaries may + // span to multiple text segments, so the mapping is inserted only on the + // first occurrence. + if (!BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo)).second) + assert(MMapInfo.BaseAddress == BinaryMMapInfo[MMapInfo.PID].BaseAddress && + "Base address on multiple segment mappings should match"); + + // Update mapping size. + const uint64_t EndAddress = MMapInfo.MMapAddress + MMapInfo.Size; + const uint64_t Size = EndAddress - BinaryMMapInfo[MMapInfo.PID].BaseAddress; + if (Size > BinaryMMapInfo[MMapInfo.PID].Size) + BinaryMMapInfo[MMapInfo.PID].Size = Size; } if (BinaryMMapInfo.empty()) { diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index 1b5ba8b49d363..308881081321a 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -1691,7 +1691,8 @@ namespace { std::unique_ptr createDwarfOnlyBC(const object::ObjectFile &File) { return cantFail(BinaryContext::createBinaryContext( - File.makeTriple(), File.getFileName(), nullptr, false, + File.makeTriple(), std::make_shared(), + File.getFileName(), nullptr, false, DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, "", WithColor::defaultErrorHandler, WithColor::defaultWarningHandler), diff --git a/bolt/lib/Rewrite/JITLinkLinker.cpp b/bolt/lib/Rewrite/JITLinkLinker.cpp index be8f9dd03467e..ba483ae4711df 100644 --- a/bolt/lib/Rewrite/JITLinkLinker.cpp +++ b/bolt/lib/Rewrite/JITLinkLinker.cpp @@ -122,7 +122,7 @@ struct JITLinkLinker::Context : jitlink::JITLinkContext { jitlink::AsyncLookupResult AllResults; for (const auto &Symbol : Symbols) { - std::string SymName = Symbol.first.str(); + std::string SymName = (*Symbol.first).str(); LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n"); if (auto Address = Linker.lookupSymbol(SymName)) { @@ -167,7 +167,9 @@ struct JITLinkLinker::Context : jitlink::JITLinkContext { Error notifyResolved(jitlink::LinkGraph &G) override { for (auto *Symbol : G.defined_symbols()) { SymbolInfo Info{Symbol->getAddress().getValue(), Symbol->getSize()}; - Linker.Symtab.insert({Symbol->getName().str(), Info}); + auto Name = + Symbol->hasName() ? (*Symbol->getName()).str() : std::string(); + Linker.Symtab.insert({std::move(Name), Info}); } return Error::success(); @@ -189,7 +191,7 @@ JITLinkLinker::~JITLinkLinker() { cantFail(MM->deallocate(std::move(Allocs))); } void JITLinkLinker::loadObject(MemoryBufferRef Obj, SectionsMapper MapSections) { - auto LG = jitlink::createLinkGraphFromObject(Obj); + auto LG = jitlink::createLinkGraphFromObject(Obj, BC.getSymbolStringPool()); if (auto E = LG.takeError()) { errs() << "BOLT-ERROR: JITLink failed: " << E << '\n'; exit(1); diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp index c328232de61a3..2f05b03290ba3 100644 --- a/bolt/lib/Rewrite/MachORewriteInstance.cpp +++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp @@ -74,7 +74,8 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile, ErrorAsOutParameter EAO(&Err); Relocation::Arch = InputFile->makeTriple().getArch(); auto BCOrErr = BinaryContext::createBinaryContext( - InputFile->makeTriple(), InputFile->getFileName(), nullptr, + InputFile->makeTriple(), std::make_shared(), + InputFile->getFileName(), nullptr, /* IsPIC */ true, DWARFContext::create(*InputFile), {llvm::outs(), llvm::errs()}); if (Error E = BCOrErr.takeError()) { diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 7059a3dd23109..76e1f0156f828 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -356,7 +356,8 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc, Relocation::Arch = TheTriple.getArch(); auto BCOrErr = BinaryContext::createBinaryContext( - TheTriple, File->getFileName(), Features.get(), IsPIC, + TheTriple, std::make_shared(), File->getFileName(), + Features.get(), IsPIC, DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, opts::DWPPathName, WithColor::defaultErrorHandler, @@ -2927,6 +2928,23 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection, LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n"); } +static BinaryFunction *getInitFunctionIfStaticBinary(BinaryContext &BC) { + // Workaround for https://github.com/llvm/llvm-project/issues/100096 + // ("[BOLT] GOT array pointer incorrectly rewritten"). In aarch64 + // static glibc binaries, the .init section's _init function pointer can + // alias with a data pointer for the end of an array. GOT rewriting + // currently can't detect this and updates the data pointer to the + // moved _init, causing a runtime crash. Skipping _init on the other + // hand should be harmless. + if (!BC.IsStaticExecutable) + return nullptr; + const BinaryData *BD = BC.getBinaryDataByName("_init"); + if (!BD || BD->getSectionName() != ".init") + return nullptr; + LLVM_DEBUG(dbgs() << "BOLT-DEBUG: skip _init in for GOT workaround.\n"); + return BC.getBinaryFunctionAtAddress(BD->getAddress()); +} + void RewriteInstance::selectFunctionsToProcess() { // Extend the list of functions to process or skip from a file. auto populateFunctionNames = [](cl::opt &FunctionNamesFile, @@ -3047,6 +3065,9 @@ void RewriteInstance::selectFunctionsToProcess() { return true; }; + if (BinaryFunction *Init = getInitFunctionIfStaticBinary(*BC)) + Init->setIgnored(); + for (auto &BFI : BC->getBinaryFunctions()) { BinaryFunction &Function = BFI.second; diff --git a/bolt/test/AArch64/check-init-not-moved.s b/bolt/test/AArch64/check-init-not-moved.s new file mode 100644 index 0000000000000..ad4b80d2e60e2 --- /dev/null +++ b/bolt/test/AArch64/check-init-not-moved.s @@ -0,0 +1,43 @@ +# Regression test for https://github.com/llvm/llvm-project/issues/100096 +# static glibc binaries crash on startup because _init is moved and +# shares its address with an array end pointer. The GOT rewriting can't +# tell the two pointers apart and incorrectly updates the _array_end +# address. Test checks that _init is not moved. + +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static -Wl,--section-start=.data=0x1000 -Wl,--section-start=.init=0x1004 +# RUN: llvm-bolt %t.exe -o %t.bolt +# RUN: llvm-nm %t.exe | FileCheck --check-prefix=CHECK-ORIGINAL %s +# RUN: llvm-nm %t.bolt | FileCheck --check-prefix=CHECK-BOLTED %s + +.section .data +.globl _array_end +_array_start: + .word 0x0 + +_array_end: +.section .init,"ax",@progbits +.globl _init + +# Check that bolt doesn't move _init. +# +# CHECK-ORIGINAL: 0000000000001004 T _init +# CHECK-BOLTED: 0000000000001004 T _init +_init: + ret + +.section .text,"ax",@progbits +.globl _start + +# Check that bolt is moving some other functions. +# +# CHECK-ORIGINAL: 0000000000001008 T _start +# CHECK-BOLTED-NOT: 0000000000001008 T _start +_start: + bl _init + adrp x0, #:got:_array_end + ldr x0, [x0, #:gotpage_lo15:_array_end] + adrp x0, #:got:_init + ldr x0, [x0, #:gotpage_lo15:_init] + ret + diff --git a/bolt/test/AArch64/veneer-lld-abs.s b/bolt/test/AArch64/veneer-lld-abs.s index d10ff46e2cb01..7e6fe2d127060 100644 --- a/bolt/test/AArch64/veneer-lld-abs.s +++ b/bolt/test/AArch64/veneer-lld-abs.s @@ -1,5 +1,5 @@ -## Check that llvm-bolt correctly recognizes long absolute thunks generated -## by LLD. +## Check that llvm-bolt correctly recognizes veneers/thunks for absolute code +## generated by LLD. # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o # RUN: %clang %cflags -fno-PIC -no-pie %t.o -o %t.exe -nostdlib \ @@ -12,40 +12,63 @@ .text .balign 4 -.global foo -.type foo, %function -foo: - adrp x1, foo +.global far_function +.type far_function, %function +far_function: ret -.size foo, .-foo +.size far_function, .-far_function + +.global near_function +.type near_function, %function +near_function: + ret +.size near_function, .-near_function + +## Force relocations against .text. +.reloc 0, R_AARCH64_NONE .section ".mytext", "ax" .balign 4 -.global __AArch64AbsLongThunk_foo -.type __AArch64AbsLongThunk_foo, %function -__AArch64AbsLongThunk_foo: +## This version of a thunk is always generated by LLD for function calls +## spanning more than 256MB. +.global __AArch64AbsLongThunk_far_function +.type __AArch64AbsLongThunk_far_function, %function +__AArch64AbsLongThunk_far_function: ldr x16, .L1 br x16 -# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_foo>: +# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_far_function>: # CHECK-INPUT-NEXT: ldr # CHECK-INPUT-NEXT: br .L1: - .quad foo -.size __AArch64AbsLongThunk_foo, .-__AArch64AbsLongThunk_foo + .quad far_function +.size __AArch64AbsLongThunk_far_function, .-__AArch64AbsLongThunk_far_function + +## If a callee is closer than 256MB away, LLD may generate a thunk with a direct +## jump to the callee. Note, that the name might still include "AbsLong". +.global __AArch64AbsLongThunk_near_function +.type __AArch64AbsLongThunk_near_function, %function +__AArch64AbsLongThunk_near_function: + b near_function +# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_near_function>: +# CHECK-INPUT-NEXT: b {{.*}} +.size __AArch64AbsLongThunk_near_function, .-__AArch64AbsLongThunk_near_function -## Check that the thunk was removed from .text and _start() calls foo() +## Check that thunks were removed from .text, and _start calls functions ## directly. -# CHECK-OUTPUT-NOT: __AArch64AbsLongThunk_foo +# CHECK-OUTPUT-NOT: __AArch64AbsLongThunk_{{.*}} .global _start .type _start, %function _start: # CHECK-INPUT-LABEL: <_start>: # CHECK-OUTPUT-LABEL: <_start>: - bl __AArch64AbsLongThunk_foo -# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_foo> -# CHECK-OUTPUT-NEXT: bl {{.*}} + bl __AArch64AbsLongThunk_far_function + bl __AArch64AbsLongThunk_near_function +# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_far_function> +# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_near_function> +# CHECK-OUTPUT-NEXT: bl {{.*}} +# CHECK-OUTPUT-NEXT: bl {{.*}} ret .size _start, .-_start diff --git a/bolt/test/X86/dwarf5-debug-names-union.test b/bolt/test/X86/dwarf5-debug-names-union.test new file mode 100644 index 0000000000000..c6da1db684ddc --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-union.test @@ -0,0 +1,496 @@ +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o +# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe +# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections +# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt +# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s + +## This test checks that bolt correctly generates entry for DW_TAG_union_type for .debug_name section. + +# BOLT: Abbreviations [ +# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] { +# BOLT-NEXT: Tag: DW_TAG_subprogram +# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present +# BOLT-NEXT: } +# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] { +# BOLT-NEXT: Tag: DW_TAG_base_type +# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present +# BOLT-NEXT: } +# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] { +# BOLT-NEXT: Tag: DW_TAG_union_type +# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4 +# BOLT-NEXT: } +# BOLT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] { +# BOLT-NEXT: Tag: DW_TAG_structure_type +# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4 +# BOLT-NEXT: } +# BOLT-NEXT: ] +# BOLT-NEXT: Bucket 0 [ +# BOLT-NEXT: EMPTY +# BOLT-NEXT: ] +# BOLT-NEXT: Bucket 1 [ +# BOLT-NEXT: Name 1 { +# BOLT-NEXT: Hash: 0x7C9A7F6A +# BOLT-NEXT: String: {{.+}} "main" +# BOLT-NEXT: Entry @ [[ENTRY:0x[0-9a-f]*]] { +# BOLT-NEXT: Abbrev: [[ABBREV1]] +# BOLT-NEXT: Tag: DW_TAG_subprogram +# BOLT-NEXT: DW_IDX_die_offset: 0x00000024 +# BOLT-NEXT: DW_IDX_parent: +# BOLT-NEXT: } +# BOLT-NEXT: } +# BOLT-NEXT: ] +# BOLT-NEXT: Bucket 2 [ +# BOLT-NEXT: EMPTY +# BOLT-NEXT: ] +# BOLT-NEXT: Bucket 3 [ +# BOLT-NEXT: Name 2 { +# BOLT-NEXT: Hash: 0xB888030 +# BOLT-NEXT: String: {{.+}} "int" +# BOLT-NEXT: Entry @ {{.+}} { +# BOLT-NEXT: Abbrev: [[ABBREV2]] +# BOLT-NEXT: Tag: DW_TAG_base_type +# BOLT-NEXT: DW_IDX_die_offset: 0x00000083 +# BOLT-NEXT: DW_IDX_parent: +# BOLT-NEXT: } +# BOLT-NEXT: } +# BOLT-NEXT: Name 3 { +# BOLT-NEXT: Hash: 0xED0F01B4 +# BOLT-NEXT: String: {{.+}} "MyUnion" +# BOLT-NEXT: Entry @ {{.+}} { +# BOLT-NEXT: Abbrev: [[ABBREV3]] +# BOLT-NEXT: Tag: DW_TAG_union_type +# BOLT-NEXT: DW_IDX_die_offset: 0x00000049 +# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]] +# BOLT-NEXT: } +# BOLT-NEXT: } +# BOLT-NEXT: ] +# BOLT-NEXT: Bucket 4 [ +# BOLT-NEXT: Name 4 { +# BOLT-NEXT: Hash: 0x8AB681F0 +# BOLT-NEXT: String: {{.+}} "MyStruct" +# BOLT-NEXT: Entry @ [[ENTRY2:0x[0-9a-f]*]] { +# BOLT-NEXT: Abbrev: [[ABBREV4]] +# BOLT-NEXT: Tag: DW_TAG_structure_type +# BOLT-NEXT: DW_IDX_die_offset: 0x00000062 +# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]] +# BOLT-NEXT: } +# BOLT-NEXT: } +# BOLT-NEXT: Name 5 { +# BOLT-NEXT: Hash: 0x8EEF3866 +# BOLT-NEXT: String: {{.+}} "MyUnion2" +# BOLT-NEXT: Entry @ {{.+}} { +# BOLT-NEXT: Abbrev: [[ABBREV3]] +# BOLT-NEXT: Tag: DW_TAG_union_type +# BOLT-NEXT: DW_IDX_die_offset: 0x00000071 +# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY2]] + + +## int main() { +## union MyUnion { +## int a; +## int b; +## }; +## struct MyStruct { +## union MyUnion2 { +## int a; +## }; +## MyUnion2 myUnion2; +## }; +## MyUnion myEnum; +## myEnum.a = 5; +## MyStruct myStruct; +## return myEnum.a + myStruct.myUnion2.a; +## } + + .text + .file "main.cpp" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .file 0 "union" "main.cpp" md5 0xb75b2512f2daa57bbcfe0c29f56d95f4 + .loc 0 1 0 # main.cpp:1:0 + retq +.Lfunc_end0: + .size main, .-main + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 23 # DW_TAG_union_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 13 # DW_TAG_member + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 56 # DW_AT_data_member_location + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 19 # DW_TAG_structure_type + .byte 1 # DW_CHILDREN_yes + .byte 54 # DW_AT_calling_convention + .byte 11 # DW_FORM_data1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x7b DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 2 # Abbrev [2] 0x23:0x5f DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 130 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x32:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 12 # DW_AT_decl_line + .long 72 # DW_AT_type + .byte 3 # Abbrev [3] 0x3d:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 97 # DW_AT_type + .byte 4 # Abbrev [4] 0x48:0x19 DW_TAG_union_type + .byte 5 # DW_AT_calling_convention + .byte 8 # DW_AT_name + .byte 4 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .byte 5 # Abbrev [5] 0x4e:0x9 DW_TAG_member + .byte 6 # DW_AT_name + .long 130 # DW_AT_type + .byte 0 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 0 # DW_AT_data_member_location + .byte 5 # Abbrev [5] 0x57:0x9 DW_TAG_member + .byte 7 # DW_AT_name + .long 130 # DW_AT_type + .byte 0 # DW_AT_decl_file + .byte 4 # DW_AT_decl_line + .byte 0 # DW_AT_data_member_location + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x61:0x20 DW_TAG_structure_type + .byte 5 # DW_AT_calling_convention + .byte 12 # DW_AT_name + .byte 4 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .byte 5 # Abbrev [5] 0x67:0x9 DW_TAG_member + .byte 10 # DW_AT_name + .long 112 # DW_AT_type + .byte 0 # DW_AT_decl_file + .byte 10 # DW_AT_decl_line + .byte 0 # DW_AT_data_member_location + .byte 4 # Abbrev [4] 0x70:0x10 DW_TAG_union_type + .byte 5 # DW_AT_calling_convention + .byte 11 # DW_AT_name + .byte 4 # DW_AT_byte_size + .byte 0 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .byte 5 # Abbrev [5] 0x76:0x9 DW_TAG_member + .byte 6 # DW_AT_name + .long 130 # DW_AT_type + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .byte 0 # DW_AT_data_member_location + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 7 # Abbrev [7] 0x82:0x4 DW_TAG_base_type + .byte 4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str_offsets,"",@progbits + .long 56 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 20.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "union" # string offset=33 +.Linfo_string3: + .asciz "main" # string offset=77 +.Linfo_string4: + .asciz "int" # string offset=82 +.Linfo_string5: + .asciz "myEnum" # string offset=86 +.Linfo_string6: + .asciz "MyUnion" # string offset=93 +.Linfo_string7: + .asciz "a" # string offset=101 +.Linfo_string8: + .asciz "b" # string offset=103 +.Linfo_string9: + .asciz "myStruct" # string offset=105 +.Linfo_string10: + .asciz "MyStruct" # string offset=114 +.Linfo_string11: + .asciz "myUnion2" # string offset=123 +.Linfo_string12: + .asciz "MyUnion2" # string offset=132 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string6 + .long .Linfo_string9 + .long .Linfo_string11 + .long .Linfo_string12 + .long .Linfo_string10 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 0 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 5 # Header: bucket count + .long 5 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long 0 # Bucket 0 + .long 1 # Bucket 1 + .long 0 # Bucket 2 + .long 2 # Bucket 3 + .long 4 # Bucket 4 + .long 2090499946 # Hash in Bucket 1 + .long 193495088 # Hash in Bucket 3 + .long -317783628 # Hash in Bucket 3 + .long -1967750672 # Hash in Bucket 4 + .long -1896925082 # Hash in Bucket 4 + .long .Linfo_string3 # String in Bucket 1: main + .long .Linfo_string4 # String in Bucket 3: int + .long .Linfo_string6 # String in Bucket 3: MyUnion + .long .Linfo_string10 # String in Bucket 4: MyStruct + .long .Linfo_string12 # String in Bucket 4: MyUnion2 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1 + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 23 # DW_TAG_union_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 4 # Abbrev code + .byte 19 # DW_TAG_structure_type + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames0: +.L3: + .byte 1 # Abbreviation code + .long 35 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames1: +.L1: + .byte 2 # Abbreviation code + .long 130 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames2: +.L4: + .byte 3 # Abbreviation code + .long 72 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: MyUnion +.Lnames3: +.L2: + .byte 4 # Abbreviation code + .long 97 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: MyStruct +.Lnames4: +.L0: + .byte 3 # Abbreviation code + .long 112 # DW_IDX_die_offset + .long .L2-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: MyUnion2 + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 20.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp index 05b898d34af56..9819a8c2b777b 100644 --- a/bolt/unittests/Core/BinaryContext.cpp +++ b/bolt/unittests/Core/BinaryContext.cpp @@ -48,7 +48,8 @@ struct BinaryContextTester : public testing::TestWithParam { void initializeBOLT() { Relocation::Arch = ObjFile->makeTriple().getArch(); BC = cantFail(BinaryContext::createBinaryContext( - ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + ObjFile->makeTriple(), std::make_shared(), + ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); } @@ -216,4 +217,4 @@ TEST_P(BinaryContextTester, BaseAddressSegmentsSmallerThanAlignment) { BC->getBaseAddressForMapping(0xaaaaaaab1000, 0x1000); ASSERT_TRUE(BaseAddress.has_value()); ASSERT_EQ(*BaseAddress, 0xaaaaaaaa0000ULL); -} \ No newline at end of file +} diff --git a/bolt/unittests/Core/CMakeLists.txt b/bolt/unittests/Core/CMakeLists.txt index bad7108dad0b7..208cf6ced7358 100644 --- a/bolt/unittests/Core/CMakeLists.txt +++ b/bolt/unittests/Core/CMakeLists.txt @@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS add_bolt_unittest(CoreTests BinaryContext.cpp MCPlusBuilder.cpp + MemoryMaps.cpp DynoStats.cpp DISABLE_LLVM_LINK_LLVM_DYLIB @@ -17,6 +18,8 @@ target_link_libraries(CoreTests PRIVATE LLVMBOLTCore LLVMBOLTRewrite + LLVMBOLTProfile + LLVMTestingSupport ) foreach (tgt ${BOLT_TARGETS_TO_BUILD}) diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp index c66c2d0c0fb16..5488cae366284 100644 --- a/bolt/unittests/Core/MCPlusBuilder.cpp +++ b/bolt/unittests/Core/MCPlusBuilder.cpp @@ -58,7 +58,8 @@ struct MCPlusBuilderTester : public testing::TestWithParam { void initializeBolt() { Relocation::Arch = ObjFile->makeTriple().getArch(); BC = cantFail(BinaryContext::createBinaryContext( - ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + ObjFile->makeTriple(), std::make_shared(), + ObjFile->getFileName(), nullptr, true, DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); BC->initializeTarget(std::unique_ptr( @@ -90,14 +91,15 @@ INSTANTIATE_TEST_SUITE_P(AArch64, MCPlusBuilderTester, ::testing::Values(Triple::aarch64)); TEST_P(MCPlusBuilderTester, AliasX0) { - uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0, AArch64::W0_W1, + uint64_t AliasesX0[] = {AArch64::W0, AArch64::W0_HI, + AArch64::X0, AArch64::W0_W1, AArch64::X0_X1, AArch64::X0_X1_X2_X3_X4_X5_X6_X7}; size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0); testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count); } TEST_P(MCPlusBuilderTester, AliasSmallerX0) { - uint64_t AliasesX0[] = {AArch64::W0, AArch64::X0}; + uint64_t AliasesX0[] = {AArch64::W0, AArch64::W0_HI, AArch64::X0}; size_t AliasesX0Count = sizeof(AliasesX0) / sizeof(*AliasesX0); testRegAliases(Triple::aarch64, AArch64::X0, AliasesX0, AliasesX0Count, true); } diff --git a/bolt/unittests/Core/MemoryMaps.cpp b/bolt/unittests/Core/MemoryMaps.cpp new file mode 100644 index 0000000000000..06073d0a82e14 --- /dev/null +++ b/bolt/unittests/Core/MemoryMaps.cpp @@ -0,0 +1,143 @@ +//===- bolt/unittest/Core/MemoryMaps.cpp ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "bolt/Core/BinaryContext.h" +#include "bolt/Profile/DataAggregator.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; +using namespace bolt; + +namespace opts { +extern cl::opt ReadPerfEvents; +} // namespace opts + +namespace { + +/// Perform checks on memory map events normally captured in perf. Tests use +/// the 'opts::ReadPerfEvents' flag to emulate these events, passing a custom +/// 'perf script' output to DataAggregator. +struct MemoryMapsTester : public testing::TestWithParam { + void SetUp() override { + initalizeLLVM(); + prepareElf(); + initializeBOLT(); + } + +protected: + void initalizeLLVM() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllDisassemblers(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + } + + void prepareElf() { + memcpy(ElfBuf, "\177ELF", 4); + ELF64LE::Ehdr *EHdr = reinterpret_cast(ElfBuf); + EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64; + EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB; + EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64; + MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF"); + ObjFile = cantFail(ObjectFile::createObjectFile(Source)); + } + + void initializeBOLT() { + Relocation::Arch = ObjFile->makeTriple().getArch(); + BC = cantFail(BinaryContext::createBinaryContext( + ObjFile->makeTriple(), std::make_shared(), + ObjFile->getFileName(), nullptr, true, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); + ASSERT_FALSE(!BC); + } + + char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {}; + std::unique_ptr ObjFile; + std::unique_ptr BC; +}; +} // namespace + +#ifdef X86_AVAILABLE + +INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester, + ::testing::Values(Triple::x86_64)); + +#endif + +#ifdef AARCH64_AVAILABLE + +INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester, + ::testing::Values(Triple::aarch64)); + +#endif + +/// Check that the correct mmap size is computed when we have multiple text +/// segment mappings. +TEST_P(MemoryMapsTester, ParseMultipleSegments) { + const int Pid = 1234; + StringRef Filename = "BINARY"; + opts::ReadPerfEvents = formatv( + "name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: " + "[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n" + "name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: " + "[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n", + Pid, Filename); + + BC->SegmentMapInfo[0x11da000] = + SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true}; + BC->SegmentMapInfo[0x31d0000] = + SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000, true}; + + DataAggregator DA(""); + BC->setFilename(Filename); + Error Err = DA.preprocessProfile(*BC); + + // Ignore errors from perf2bolt when parsing memory events later on. + ASSERT_THAT_ERROR(std::move(Err), Succeeded()); + + auto &BinaryMMapInfo = DA.getBinaryMMapInfo(); + auto El = BinaryMMapInfo.find(Pid); + // Check that memory mapping is present and has the expected size. + ASSERT_NE(El, BinaryMMapInfo.end()); + ASSERT_EQ(El->second.Size, static_cast(0xb1d0000)); +} + +/// Check that DataAggregator aborts when pre-processing an input binary +/// with multiple text segments that have different base addresses. +TEST_P(MemoryMapsTester, MultipleSegmentsMismatchedBaseAddress) { + const int Pid = 1234; + StringRef Filename = "BINARY"; + opts::ReadPerfEvents = formatv( + "name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: " + "[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n" + "name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: " + "[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n", + Pid, Filename); + + BC->SegmentMapInfo[0x11da000] = + SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true}; + // Using '0x31d0fff' FileOffset which triggers a different base address + // for this second text segment. + BC->SegmentMapInfo[0x31d0000] = + SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0fff, 0x3000000, 0x200000, true}; + + DataAggregator DA(""); + BC->setFilename(Filename); + ASSERT_DEBUG_DEATH( + { Error Err = DA.preprocessProfile(*BC); }, + "Base address on multiple segment mappings should match"); +} diff --git a/clang-tools-extra/CODE_OWNERS.TXT b/clang-tools-extra/CODE_OWNERS.TXT deleted file mode 100644 index 2831ec7e25f59..0000000000000 --- a/clang-tools-extra/CODE_OWNERS.TXT +++ /dev/null @@ -1,30 +0,0 @@ -This file is a list of the people responsible for ensuring that patches for a -particular tool are reviewed, either by themself or by someone else. They are -also the gatekeepers for their part of Clang, with the final word on what goes -in or not. - -The list is sorted by surname and formatted to allow easy grepping and -beautification by scripts. The fields are: name (N), email (E), Phabricator -handle (H), and description (D). - -N: Aaron Ballman -E: aaron@aaronballman.com -H: aaron.ballman -D: clang-query - -N: Julie Hockett -E: juliehockett@google.com -D: clang-doc - -N: Nathan James -E: n.james93@hotmail.co.uk -H: njames93 -D: clang-tidy - -N: Manuel Klimek -E: klimek@google.com -D: all parts of clang-tools-extra not covered by someone else - -N: Sam McCall -E: sammccall@google.com -D: clangd diff --git a/clang-tools-extra/Maintainers.txt b/clang-tools-extra/Maintainers.txt new file mode 100644 index 0000000000000..689f2408820e9 --- /dev/null +++ b/clang-tools-extra/Maintainers.txt @@ -0,0 +1,75 @@ +============================= +Clang Tools Extra Maintainers +============================= + +This file is a list of the maintainers +(https://llvm.org/docs/DeveloperPolicy.html#maintainers) for clang-tools-extra. + + +Active Maintainers +================== +The following people are the active maintainers for the project. Please reach +out to them for code reviews, questions about their area of expertise, or other +assistance. + +Lead Maintainer +--------------- +| Aaron Ballman +| aaron@aaronballman.com (email), aaron.ballman (Phabricator), AaronBallman (GitHub), AaronBallman (Discourse), aaronballman (Discord), AaronBallman (IRC) + + +clang-tidy +---------- +| Congcong Cai +| congcongcai0907@163.com (email), HerrCai0907 (GitHub), HerrCai0907 (Discourse) + +| Julian Schmidt +| git.julian.schmidt@gmail.com (email), 5chmidti (GitHub), 5chmidti (Discourse), 5chmidti (Discord) + +| Piotr Zegar +| me@piotrzegar.pl (email), PiotrZSL (GitHub), PiotrZSL (Discourse), PiotrZSL (Discord) + + +clang-query +----------- +| Aaron Ballman +| aaron@aaronballman.com (email), aaron.ballman (Phabricator), AaronBallman (GitHub), AaronBallman (Discourse), aaronballman (Discord), AaronBallman (IRC) + + +clang-doc +--------- +| Paul Kirth +| paulkirth@google.com (email), ilovepi (GitHub), ilovepi (Discourse) + +| Peter Chou +| peterchou411@gmail.com (email), PeterChou1 (GitHub), PeterChou1 (Discourse), .peterchou (Discord) + + +clangd +------ +| Nathan Ridge +| zeratul976@hotmail.com (email), HighCommander4 (GitHub), HighCommander4 (Discourse), nridge (Discord) + +| Chris Bieneman +| chris.bieneman@gmail.com (email), llvm-beanz (GitHub), beanz (Discord), beanz (Discourse) + +| Kadir Çetinkaya +| kadircet@google.com (email), kadircet (GitHub) kadircet (Discourse), kadircet (Discord) + + +Inactive Maintainers +==================== +The following people have graciously spent time performing maintainership +responsibilities but are no longer active in that role. Thank you for all your +help with the success of the project! + +Emeritus Lead Maintainers +------------------------- +| Manuel Klimek (klimek@google.com (email), r4nt (GitHub)) + + +Inactive component maintainers +------------------------------ +| Nathan James (n.james93@hotmail.co.uk) -- clang-tidy +| Julie Hockett (juliehockett@google.com) -- clang-doc +| Sam McCall (sammccall@google.com (email), sam-mccall (GitHub, Discourse, Discord)) -- clangd diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp index 346437e20322e..dc3a3b6211b7e 100644 --- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -116,6 +116,28 @@ findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer, return Results; } +/// Returns the full source range for the field declaration up to (not +/// including) the trailing semicolumn, including potential macro invocations, +/// e.g. `int a GUARDED_BY(mu);`. +static SourceRange getFullFieldSourceRange(const FieldDecl &Field, + const ASTContext &Context) { + SourceRange Range = Field.getSourceRange(); + SourceLocation End = Range.getEnd(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + while (true) { + std::optional CurrentToken = Lexer::findNextToken(End, SM, LangOpts); + + if (!CurrentToken || CurrentToken->is(tok::semi)) + break; + + if (CurrentToken->is(tok::eof)) + return Range; // Something is wrong, return the original range. + End = CurrentToken->getLastLoc(); + } + return SourceRange(Range.getBegin(), End); +} + /// Reorders fields in the definition of a struct/class. /// /// At the moment reordering of fields with @@ -145,9 +167,10 @@ static bool reorderFieldsInDefinition( const auto FieldIndex = Field->getFieldIndex(); if (FieldIndex == NewFieldsOrder[FieldIndex]) continue; - addReplacement(Field->getSourceRange(), - Fields[NewFieldsOrder[FieldIndex]]->getSourceRange(), - Context, Replacements); + addReplacement( + getFullFieldSourceRange(*Field, Context), + getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context), + Context, Replacements); } return true; } diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 97e16a12febd0..ff42f96a0477b 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -81,6 +81,9 @@ class ClangTidyContext { ~ClangTidyContext(); + ClangTidyContext(const ClangTidyContext &) = delete; + ClangTidyContext &operator=(const ClangTidyContext &) = delete; + /// Report any errors detected using this method. /// /// This is still under heavy development and will likely change towards using diff --git a/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h b/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h index e862195abaabb..f66285672d04a 100644 --- a/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h +++ b/clang-tools-extra/clang-tidy/NoLintDirectiveHandler.h @@ -31,6 +31,8 @@ class NoLintDirectiveHandler { public: NoLintDirectiveHandler(); ~NoLintDirectiveHandler(); + NoLintDirectiveHandler(const NoLintDirectiveHandler &) = delete; + NoLintDirectiveHandler &operator=(const NoLintDirectiveHandler &) = delete; bool shouldSuppress(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Diag, llvm::StringRef DiagName, diff --git a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp index 356acf968db92..a7e25141b3fe2 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp @@ -102,6 +102,212 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) { this); Finder->addMatcher(switchStmt().bind("switch"), this); Finder->addMatcher(conditionalOperator().bind("condOp"), this); + Finder->addMatcher( + ifStmt((hasThen(hasDescendant(ifStmt())))).bind("ifWithDescendantIf"), + this); +} + +/// Determines whether two statement trees are identical regarding +/// operators and symbols. +/// +/// Exceptions: expressions containing macros or functions with possible side +/// effects are never considered identical. +/// Limitations: (t + u) and (u + t) are not considered identical. +/// t*(u + t) and t*u + t*t are not considered identical. +/// +static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, + const Stmt *Stmt2, bool IgnoreSideEffects) { + + if (!Stmt1 || !Stmt2) + return !Stmt1 && !Stmt2; + + // If Stmt1 & Stmt2 are of different class then they are not + // identical statements. + if (Stmt1->getStmtClass() != Stmt2->getStmtClass()) + return false; + + const auto *Expr1 = dyn_cast(Stmt1); + const auto *Expr2 = dyn_cast(Stmt2); + + if (Expr1 && Expr2) { + // If Stmt1 has side effects then don't warn even if expressions + // are identical. + if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx) && + Expr2->HasSideEffects(Ctx)) + return false; + // If either expression comes from a macro then don't warn even if + // the expressions are identical. + if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) + return false; + + // If all children of two expressions are identical, return true. + Expr::const_child_iterator I1 = Expr1->child_begin(); + Expr::const_child_iterator I2 = Expr2->child_begin(); + while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { + if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects)) + return false; + ++I1; + ++I2; + } + // If there are different number of children in the statements, return + // false. + if (I1 != Expr1->child_end()) + return false; + if (I2 != Expr2->child_end()) + return false; + } + + switch (Stmt1->getStmtClass()) { + default: + return false; + case Stmt::CallExprClass: + case Stmt::ArraySubscriptExprClass: + case Stmt::ArraySectionExprClass: + case Stmt::OMPArrayShapingExprClass: + case Stmt::OMPIteratorExprClass: + case Stmt::ImplicitCastExprClass: + case Stmt::ParenExprClass: + case Stmt::BreakStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::NullStmtClass: + return true; + case Stmt::CStyleCastExprClass: { + const auto *CastExpr1 = cast(Stmt1); + const auto *CastExpr2 = cast(Stmt2); + + return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten(); + } + case Stmt::ReturnStmtClass: { + const auto *ReturnStmt1 = cast(Stmt1); + const auto *ReturnStmt2 = cast(Stmt2); + + return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(), + ReturnStmt2->getRetValue(), IgnoreSideEffects); + } + case Stmt::ForStmtClass: { + const auto *ForStmt1 = cast(Stmt1); + const auto *ForStmt2 = cast(Stmt2); + + if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::DoStmtClass: { + const auto *DStmt1 = cast(Stmt1); + const auto *DStmt2 = cast(Stmt2); + + if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::WhileStmtClass: { + const auto *WStmt1 = cast(Stmt1); + const auto *WStmt2 = cast(Stmt2); + + if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::IfStmtClass: { + const auto *IStmt1 = cast(Stmt1); + const auto *IStmt2 = cast(Stmt2); + + if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(), + IgnoreSideEffects)) + return false; + if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(), + IgnoreSideEffects)) + return false; + return true; + } + case Stmt::CompoundStmtClass: { + const auto *CompStmt1 = cast(Stmt1); + const auto *CompStmt2 = cast(Stmt2); + + if (CompStmt1->size() != CompStmt2->size()) + return false; + + if (!llvm::all_of(llvm::zip(CompStmt1->body(), CompStmt2->body()), + [&Ctx, IgnoreSideEffects]( + std::tuple stmtPair) { + const Stmt *stmt0 = std::get<0>(stmtPair); + const Stmt *stmt1 = std::get<1>(stmtPair); + return isIdenticalStmt(Ctx, stmt0, stmt1, + IgnoreSideEffects); + })) { + return false; + } + + return true; + } + case Stmt::CompoundAssignOperatorClass: + case Stmt::BinaryOperatorClass: { + const auto *BinOp1 = cast(Stmt1); + const auto *BinOp2 = cast(Stmt2); + return BinOp1->getOpcode() == BinOp2->getOpcode(); + } + case Stmt::CharacterLiteralClass: { + const auto *CharLit1 = cast(Stmt1); + const auto *CharLit2 = cast(Stmt2); + return CharLit1->getValue() == CharLit2->getValue(); + } + case Stmt::DeclRefExprClass: { + const auto *DeclRef1 = cast(Stmt1); + const auto *DeclRef2 = cast(Stmt2); + return DeclRef1->getDecl() == DeclRef2->getDecl(); + } + case Stmt::IntegerLiteralClass: { + const auto *IntLit1 = cast(Stmt1); + const auto *IntLit2 = cast(Stmt2); + + llvm::APInt I1 = IntLit1->getValue(); + llvm::APInt I2 = IntLit2->getValue(); + if (I1.getBitWidth() != I2.getBitWidth()) + return false; + return I1 == I2; + } + case Stmt::FloatingLiteralClass: { + const auto *FloatLit1 = cast(Stmt1); + const auto *FloatLit2 = cast(Stmt2); + return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); + } + case Stmt::StringLiteralClass: { + const auto *StringLit1 = cast(Stmt1); + const auto *StringLit2 = cast(Stmt2); + return StringLit1->getBytes() == StringLit2->getBytes(); + } + case Stmt::MemberExprClass: { + const auto *MemberStmt1 = cast(Stmt1); + const auto *MemberStmt2 = cast(Stmt2); + return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl(); + } + case Stmt::UnaryOperatorClass: { + const auto *UnaryOp1 = cast(Stmt1); + const auto *UnaryOp2 = cast(Stmt2); + return UnaryOp1->getOpcode() == UnaryOp2->getOpcode(); + } + } } void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) { @@ -269,6 +475,21 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) { return; } + if (const auto *IS = Result.Nodes.getNodeAs("ifWithDescendantIf")) { + const Stmt *Then = IS->getThen(); + auto CS = dyn_cast(Then); + if (CS && (!CS->body_empty())) { + const auto *InnerIf = dyn_cast(*CS->body_begin()); + if (InnerIf && isIdenticalStmt(Context, IS->getCond(), InnerIf->getCond(), + /*IgnoreSideEffects=*/false)) { + diag(IS->getBeginLoc(), "if with identical inner if statement"); + diag(InnerIf->getBeginLoc(), "inner if starts here", + DiagnosticIDs::Note); + } + } + return; + } + llvm_unreachable("No if statement and no switch statement."); } diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index b0a2318acc059..13adad7c3dadb 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_library(clangTidyBugproneModule STATIC ChainedComparisonCheck.cpp ComparePointerToMemberVirtualFunctionCheck.cpp CopyConstructorInitCheck.cpp + CrtpConstructorAccessibilityCheck.cpp DanglingHandleCheck.cpp DynamicStaticInitializersCheck.cpp EasilySwappableParametersCheck.cpp @@ -26,11 +27,8 @@ add_clang_library(clangTidyBugproneModule STATIC ForwardingReferenceOverloadCheck.cpp ImplicitWideningOfMultiplicationResultCheck.cpp InaccurateEraseCheck.cpp - IncorrectEnableIfCheck.cpp - ReturnConstRefFromParameterCheck.cpp - SuspiciousStringviewDataUsageCheck.cpp - SwitchMissingDefaultCaseCheck.cpp IncDecInConditionsCheck.cpp + IncorrectEnableIfCheck.cpp IncorrectRoundingsCheck.cpp InfiniteLoopCheck.cpp IntegerDivisionCheck.cpp @@ -45,8 +43,8 @@ add_clang_library(clangTidyBugproneModule STATIC MultipleNewInOneExpressionCheck.cpp MultipleStatementMacroCheck.cpp NoEscapeCheck.cpp - NondeterministicPointerIterationOrderCheck.cpp NonZeroEnumToBoolConversionCheck.cpp + NondeterministicPointerIterationOrderCheck.cpp NotNullTerminatedResultCheck.cpp OptionalValueConversionCheck.cpp ParentVirtualCallCheck.cpp @@ -54,6 +52,7 @@ add_clang_library(clangTidyBugproneModule STATIC PosixReturnCheck.cpp RedundantBranchConditionCheck.cpp ReservedIdentifierCheck.cpp + ReturnConstRefFromParameterCheck.cpp SharedPtrArrayMismatchCheck.cpp SignalHandlerCheck.cpp SignedCharMisuseCheck.cpp @@ -74,7 +73,9 @@ add_clang_library(clangTidyBugproneModule STATIC SuspiciousReallocUsageCheck.cpp SuspiciousSemicolonCheck.cpp SuspiciousStringCompareCheck.cpp + SuspiciousStringviewDataUsageCheck.cpp SwappedArgumentsCheck.cpp + SwitchMissingDefaultCaseCheck.cpp TaggedUnionMemberCountCheck.cpp TerminatingContinueCheck.cpp ThrowKeywordMissingCheck.cpp @@ -85,7 +86,6 @@ add_clang_library(clangTidyBugproneModule STATIC UnhandledExceptionAtNewCheck.cpp UnhandledSelfAssignmentCheck.cpp UniquePtrArrayMismatchCheck.cpp - CrtpConstructorAccessibilityCheck.cpp UnsafeFunctionsCheck.cpp UnusedLocalNonTrivialVariableCheck.cpp UnusedRaiiCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp index 2b2d80ea9346b..b7f0c08b2a7d4 100644 --- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp @@ -13,13 +13,15 @@ #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" #include "clang/Analysis/CallGraph.h" #include "llvm/ADT/SCCIterator.h" -#include "llvm/ADT/SmallVector.h" using namespace clang::ast_matchers; +using clang::ast_matchers::internal::Matcher; using clang::tidy::utils::hasPtrOrReferenceInFunc; namespace clang { -namespace ast_matchers { +namespace tidy::bugprone { + +namespace { /// matches a Decl if it has a "no return" attribute of any kind AST_MATCHER(Decl, declHasNoReturnAttr) { return Node.hasAttr() || Node.hasAttr() || @@ -30,23 +32,21 @@ AST_MATCHER(Decl, declHasNoReturnAttr) { AST_MATCHER(FunctionType, typeHasNoReturnAttr) { return Node.getNoReturnAttr(); } -} // namespace ast_matchers -namespace tidy::bugprone { +} // namespace -static internal::Matcher -loopEndingStmt(internal::Matcher Internal) { - internal::Matcher isNoReturnFunType = +static Matcher loopEndingStmt(Matcher Internal) { + Matcher IsNoReturnFunType = ignoringParens(functionType(typeHasNoReturnAttr())); - internal::Matcher isNoReturnDecl = - anyOf(declHasNoReturnAttr(), functionDecl(hasType(isNoReturnFunType)), - varDecl(hasType(blockPointerType(pointee(isNoReturnFunType))))); + Matcher IsNoReturnDecl = + anyOf(declHasNoReturnAttr(), functionDecl(hasType(IsNoReturnFunType)), + varDecl(hasType(blockPointerType(pointee(IsNoReturnFunType))))); return stmt(anyOf( mapAnyOf(breakStmt, returnStmt, gotoStmt, cxxThrowExpr).with(Internal), callExpr(Internal, callee(mapAnyOf(functionDecl, /* block callee */ varDecl) - .with(isNoReturnDecl))), - objcMessageExpr(Internal, callee(isNoReturnDecl)))); + .with(IsNoReturnDecl))), + objcMessageExpr(Internal, callee(IsNoReturnDecl)))); } /// Return whether `Var` was changed in `LoopStmt`. diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp index 600eab3755276..f2ff27d85fb00 100644 --- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp @@ -43,18 +43,20 @@ OptionalValueConversionCheck::getCheckTraversalKind() const { } void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) { - auto ConstructTypeMatcher = - qualType(hasCleanType(qualType().bind("optional-type"))); + auto BindOptionalType = qualType( + hasCleanType(qualType(hasDeclaration(namedDecl( + matchers::matchesAnyListedName(OptionalTypes)))) + .bind("optional-type"))); - auto CallTypeMatcher = + auto EqualsBoundOptionalType = qualType(hasCleanType(equalsBoundNode("optional-type"))); auto OptionalDereferenceMatcher = callExpr( anyOf( cxxOperatorCallExpr(hasOverloadedOperatorName("*"), - hasUnaryOperand(hasType(CallTypeMatcher))) + hasUnaryOperand(hasType(EqualsBoundOptionalType))) .bind("op-call"), - cxxMemberCallExpr(thisPointerType(CallTypeMatcher), + cxxMemberCallExpr(thisPointerType(EqualsBoundOptionalType), callee(cxxMethodDecl(anyOf( hasOverloadedOperatorName("*"), matchers::matchesAnyListedName(ValueMethods))))) @@ -66,10 +68,7 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) { hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher))); Finder->addMatcher( cxxConstructExpr( - argumentCountIs(1U), - hasDeclaration(cxxConstructorDecl( - ofClass(matchers::matchesAnyListedName(OptionalTypes)))), - hasType(ConstructTypeMatcher), + argumentCountIs(1U), hasType(BindOptionalType), hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher, StdMoveCallMatcher))), unless(anyOf(hasAncestor(typeLoc()), diff --git a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp index 7cc4fe519d3a6..295955a971d7e 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ReturnConstRefFromParameterCheck.h" +#include "clang/AST/Attrs.inc" #include "clang/AST/Expr.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -15,25 +16,35 @@ using namespace clang::ast_matchers; namespace clang::tidy::bugprone { +namespace { + +AST_MATCHER(ParmVarDecl, hasLifetimeBoundAttr) { + return Node.hasAttr(); +} + +} // namespace + void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) { const auto DRef = ignoringParens( declRefExpr( to(parmVarDecl(hasType(hasCanonicalType( qualType(lValueReferenceType(pointee( qualType(isConstQualified())))) - .bind("type")))) + .bind("type"))), + hasDeclContext(functionDecl( + equalsBoundNode("func"), + hasReturnTypeLoc(loc(qualType( + hasCanonicalType(equalsBoundNode("type"))))))), + unless(hasLifetimeBoundAttr())) .bind("param"))) .bind("dref")); - const auto Func = - functionDecl(hasReturnTypeLoc(loc( - qualType(hasCanonicalType(equalsBoundNode("type")))))) - .bind("func"); - Finder->addMatcher(returnStmt(hasReturnValue(DRef), hasAncestor(Func)), this); Finder->addMatcher( - returnStmt(hasReturnValue(ignoringParens(conditionalOperator( - eachOf(hasTrueExpression(DRef), hasFalseExpression(DRef)), - hasAncestor(Func))))), + returnStmt( + hasAncestor(functionDecl().bind("func")), + hasReturnValue(anyOf( + DRef, ignoringParens(conditionalOperator(eachOf( + hasTrueExpression(DRef), hasFalseExpression(DRef))))))), this); } diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 6bb9a349d69b1..fc35bc22c52e0 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -855,9 +855,6 @@ static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr, } // namespace void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { - const auto AnyLiteralExpr = ignoringParenImpCasts( - anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral())); - const auto BannedIntegerLiteral = integerLiteral(expandedByMacro(KnownBannedMacroNames)); const auto IsInUnevaluatedContext = expr(anyOf( @@ -866,19 +863,16 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { // Binary with equivalent operands, like (X != 2 && X != 2). Finder->addMatcher( traverse(TK_AsIs, - binaryOperator( - anyOf(isComparisonOperator(), - hasAnyOperatorName("-", "/", "%", "|", "&", "^", "&&", - "||", "=")), - operandsAreEquivalent(), - // Filter noisy false positives. - unless(isInTemplateInstantiation()), - unless(binaryOperatorIsInMacro()), - unless(hasType(realFloatingPointType())), - unless(hasEitherOperand(hasType(realFloatingPointType()))), - unless(hasLHS(AnyLiteralExpr)), - unless(hasDescendant(BannedIntegerLiteral)), - unless(IsInUnevaluatedContext)) + binaryOperator(anyOf(isComparisonOperator(), + hasAnyOperatorName("-", "/", "%", "|", "&", + "^", "&&", "||", "=")), + operandsAreEquivalent(), + // Filter noisy false positives. + unless(isInTemplateInstantiation()), + unless(binaryOperatorIsInMacro()), + unless(hasAncestor(arraySubscriptExpr())), + unless(hasDescendant(BannedIntegerLiteral)), + unless(IsInUnevaluatedContext)) .bind("binary")), this); @@ -1238,6 +1232,50 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *BinOp = Result.Nodes.getNodeAs("binary")) { // If the expression's constants are macros, check whether they are // intentional. + + // + // Special case for floating-point representation. + // + // If expressions on both sides of comparison operator are of type float, + // then for some comparison operators no warning shall be + // reported even if the expressions are identical from a symbolic point of + // view. Comparison between expressions, declared variables and literals + // are treated differently. + // + // != and == between float literals that have the same value should NOT + // warn. < > between float literals that have the same value SHOULD warn. + // + // != and == between the same float declaration should NOT warn. + // < > between the same float declaration SHOULD warn. + // + // != and == between eq. expressions that evaluates into float + // should NOT warn. + // < > between eq. expressions that evaluates into float + // should NOT warn. + // + const Expr *LHS = BinOp->getLHS()->IgnoreParenImpCasts(); + const Expr *RHS = BinOp->getRHS()->IgnoreParenImpCasts(); + const BinaryOperator::Opcode Op = BinOp->getOpcode(); + const bool OpEqualEQorNE = ((Op == BO_EQ) || (Op == BO_NE)); + + const auto *DeclRef1 = dyn_cast(LHS); + const auto *DeclRef2 = dyn_cast(RHS); + const auto *FloatLit1 = dyn_cast(LHS); + const auto *FloatLit2 = dyn_cast(RHS); + + if (DeclRef1 && DeclRef2 && + DeclRef1->getType()->hasFloatingRepresentation() && + DeclRef2->getType()->hasFloatingRepresentation() && + (DeclRef1->getDecl() == DeclRef2->getDecl()) && OpEqualEQorNE) { + return; + } + + if (FloatLit1 && FloatLit2 && + FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()) && + OpEqualEQorNE) { + return; + } + if (areSidesBinaryConstExpressions(BinOp, Result.Context)) { const Expr *LhsConst = nullptr, *RhsConst = nullptr; BinaryOperatorKind MainOpcode{}, SideOpcode{}; diff --git a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp index 71eb2d94cd4f2..1e0f398a4a560 100644 --- a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp @@ -15,7 +15,9 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/Token.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" using namespace clang::ast_matchers; @@ -78,6 +80,22 @@ AST_POLYMORPHIC_MATCHER(isExternStorageClass, return Node.getStorageClass() == SC_Extern; } +AST_MATCHER(FunctionDecl, isAllocationOrDeallocationOverloadedFunction) { + // [basic.stc.dynamic.allocation] + // An allocation function that is not a class member function shall belong to + // the global scope and not have a name with internal linkage. + // [basic.stc.dynamic.deallocation] + // A deallocation function that is not a class member function shall belong to + // the global scope and not have a name with internal linkage. + static const llvm::DenseSet OverloadedOperators{ + OverloadedOperatorKind::OO_New, + OverloadedOperatorKind::OO_Array_New, + OverloadedOperatorKind::OO_Delete, + OverloadedOperatorKind::OO_Array_Delete, + }; + return OverloadedOperators.contains(Node.getOverloadedOperator()); +} + } // namespace UseInternalLinkageCheck::UseInternalLinkageCheck(StringRef Name, @@ -100,10 +118,16 @@ void UseInternalLinkageCheck::registerMatchers(MatchFinder *Finder) { isExternStorageClass(), isExternC(), // 3. template isExplicitTemplateSpecialization(), - // 4. friend - hasAncestor(friendDecl())))); + hasAncestor(decl(anyOf( + // 4. friend + friendDecl(), + // 5. module export decl + exportDecl())))))); Finder->addMatcher( - functionDecl(Common, hasBody(), unless(cxxMethodDecl()), unless(isMain())) + functionDecl(Common, hasBody(), + unless(anyOf(cxxMethodDecl(), + isAllocationOrDeallocationOverloadedFunction(), + isMain()))) .bind("fn"), this); Finder->addMatcher(varDecl(Common, hasGlobalStorage()).bind("var"), this); diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp index 234f6790a7ed9..ab72c6796bb4c 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp @@ -20,12 +20,16 @@ using namespace clang::ast_matchers; namespace clang::tidy::modernize { static bool isNegativeComparison(const Expr *ComparisonExpr) { - if (const auto *BO = llvm::dyn_cast(ComparisonExpr)) - return BO->getOpcode() == BO_NE; + if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) + return Op->getOpcode() == BO_NE; if (const auto *Op = llvm::dyn_cast(ComparisonExpr)) return Op->getOperator() == OO_ExclaimEqual; + if (const auto *Op = + llvm::dyn_cast(ComparisonExpr)) + return Op->getOperator() == BO_NE; + return false; } @@ -185,7 +189,7 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) { // Case 6: X.substr(0, LEN(Y)) [!=]= Y -> starts_with. Finder->addMatcher( - cxxOperatorCallExpr( + binaryOperation( hasAnyOperatorName("==", "!="), hasOperands( expr().bind("needle"), diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h index 617dadce76bd3..acd8a6bfc50f5 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.h @@ -18,12 +18,10 @@ namespace clang::tidy::readability { /// a call to `empty()`. /// /// The emptiness of a container should be checked using the `empty()` method -/// instead of the `size()` method. It is not guaranteed that `size()` is a -/// constant-time function, and it is generally more efficient and also shows -/// clearer intent to use `empty()`. Furthermore some containers may implement -/// the `empty()` method but not implement the `size()` method. Using `empty()` -/// whenever possible makes it easier to switch to another container in the -/// future. +/// instead of the `size()` method. It shows clearer intent to use `empty()`. +/// Furthermore some containers may implement the `empty()` method but not +/// implement the `size()` method. Using `empty()` whenever possible makes it +/// easier to switch to another container in the future. class ContainerSizeEmptyCheck : public ClangTidyCheck { public: ContainerSizeEmptyCheck(StringRef Name, ClangTidyContext *Context); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index 05dd313d0a0d3..1e981825c7c15 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1415,6 +1415,12 @@ void ClangdLSPServer::onInlayHint(const InlayHintsParams &Params, std::move(Reply)); } +void ClangdLSPServer::onCallHierarchyOutgoingCalls( + const CallHierarchyOutgoingCallsParams &Params, + Callback> Reply) { + Server->outgoingCalls(Params.item, std::move(Reply)); +} + void ClangdLSPServer::applyConfiguration( const ConfigurationSettings &Settings) { // Per-file update to the compilation database. @@ -1693,6 +1699,8 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind, Bind.method("typeHierarchy/subtypes", this, &ClangdLSPServer::onSubTypes); Bind.method("textDocument/prepareCallHierarchy", this, &ClangdLSPServer::onPrepareCallHierarchy); Bind.method("callHierarchy/incomingCalls", this, &ClangdLSPServer::onCallHierarchyIncomingCalls); + if (Opts.EnableOutgoingCalls) + Bind.method("callHierarchy/outgoingCalls", this, &ClangdLSPServer::onCallHierarchyOutgoingCalls); Bind.method("textDocument/selectionRange", this, &ClangdLSPServer::onSelectionRange); Bind.method("textDocument/documentLink", this, &ClangdLSPServer::onDocumentLink); Bind.method("textDocument/semanticTokens/full", this, &ClangdLSPServer::onSemanticTokens); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index 0b8e4720f5323..f43734ec1ede3 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -73,6 +73,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks, /// The destructor blocks on any outstanding background tasks. ~ClangdLSPServer(); + ClangdLSPServer(const ClangdLSPServer &other) = delete; + ClangdLSPServer &operator=(const ClangdLSPServer &other) = delete; + /// Run LSP server loop, communicating with the Transport provided in the /// constructor. This method must not be executed more than once. /// @@ -156,6 +159,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks, void onCallHierarchyIncomingCalls( const CallHierarchyIncomingCallsParams &, Callback>); + void onCallHierarchyOutgoingCalls( + const CallHierarchyOutgoingCallsParams &, + Callback>); void onClangdInlayHints(const InlayHintsParams &, Callback); void onInlayHint(const InlayHintsParams &, Callback>); diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 9b38be04e7ddd..52be15d3da936 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -215,7 +215,9 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, const Options &Opts, Callbacks *Callbacks) : FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS), - DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr), + DynamicIdx(Opts.BuildDynamicSymbolIndex + ? new FileIndex(Opts.EnableOutgoingCalls) + : nullptr), ModulesManager(Opts.ModulesManager), ClangTidyProvider(Opts.ClangTidyProvider), UseDirtyHeaders(Opts.UseDirtyHeaders), @@ -256,6 +258,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, Callbacks->onBackgroundIndexProgress(S); }; BGOpts.ContextProvider = Opts.ContextProvider; + BGOpts.SupportContainedRefs = Opts.EnableOutgoingCalls; BackgroundIdx = std::make_unique( TFS, CDB, BackgroundIndexStorage::createDiskBackedStorageFactory( @@ -912,6 +915,15 @@ void ClangdServer::inlayHints(PathRef File, std::optional RestrictRange, WorkScheduler->runWithAST("InlayHints", File, std::move(Action), Transient); } +void ClangdServer::outgoingCalls( + const CallHierarchyItem &Item, + Callback> CB) { + WorkScheduler->run("Outgoing Calls", "", + [CB = std::move(CB), Item, this]() mutable { + CB(clangd::outgoingCalls(Item, Index)); + }); +} + void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) { // FIXME: Do nothing for now. This will be used for indexing and potentially // invalidating other caches. diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index a653cdb56b751..e030bf04122d5 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -110,6 +110,11 @@ class ClangdServer { /// Cached preambles are potentially large. If false, store them on disk. bool StorePreamblesInMemory = true; + /// Call hierarchy's outgoing calls feature requires additional index + /// serving structures which increase memory usage. If false, these are + /// not created and the feature is not enabled. + bool EnableOutgoingCalls = true; + /// This throttler controls which preambles may be built at a given time. clangd::PreambleThrottler *PreambleThrottler = nullptr; @@ -292,6 +297,10 @@ class ClangdServer { void incomingCalls(const CallHierarchyItem &Item, Callback>); + /// Resolve outgoing calls for a given call hierarchy item. + void outgoingCalls(const CallHierarchyItem &Item, + Callback>); + /// Resolve inlay hints for a given document. void inlayHints(PathRef File, std::optional RestrictRange, Callback>); diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp index 26d54200eeffd..9eb892e8e4a8e 100644 --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -118,6 +118,16 @@ const Type *resolveDeclsToType(const std::vector &Decls, return nullptr; } +TemplateName getReferencedTemplateName(const Type *T) { + if (const auto *TST = T->getAs()) { + return TST->getTemplateName(); + } + if (const auto *DTST = T->getAs()) { + return DTST->getTemplateName(); + } + return TemplateName(); +} + // Helper function for HeuristicResolver::resolveDependentMember() // which takes a possibly-dependent type `T` and heuristically // resolves it to a CXXRecordDecl in which we can try name lookup. @@ -142,12 +152,12 @@ CXXRecordDecl *HeuristicResolverImpl::resolveTypeToRecordDecl(const Type *T) { if (!T) return nullptr; - const auto *TST = T->getAs(); - if (!TST) + TemplateName TN = getReferencedTemplateName(T); + if (TN.isNull()) return nullptr; - const ClassTemplateDecl *TD = dyn_cast_or_null( - TST->getTemplateName().getAsTemplateDecl()); + const ClassTemplateDecl *TD = + dyn_cast_or_null(TN.getAsTemplateDecl()); if (!TD) return nullptr; diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp index 29508901f85bb..bee31fe51555e 100644 --- a/clang-tools-extra/clangd/ModulesBuilder.cpp +++ b/clang-tools-extra/clangd/ModulesBuilder.cpp @@ -199,7 +199,7 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath, SourceManager SourceMgr(*Diags, FileMgr); - HeaderSearch HeaderInfo(HSOpts, SourceMgr, *Diags, LangOpts, + HeaderSearch HeaderInfo(std::move(HSOpts), SourceMgr, *Diags, LangOpts, /*Target=*/nullptr); TrivialModuleLoader ModuleLoader; diff --git a/clang-tools-extra/clangd/ParsedAST.h b/clang-tools-extra/clangd/ParsedAST.h index 63e564bd68a78..8d9d1e6456926 100644 --- a/clang-tools-extra/clangd/ParsedAST.h +++ b/clang-tools-extra/clangd/ParsedAST.h @@ -59,6 +59,9 @@ class ParsedAST { ~ParsedAST(); + ParsedAST(const ParsedAST &Other) = delete; + ParsedAST &operator=(const ParsedAST &Other) = delete; + /// Note that the returned ast will not contain decls from the preamble that /// were not deserialized during parsing. Clients should expect only decls /// from the main file to be in the AST. diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp index 71548b59cc308..035e5e63d8fbb 100644 --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -411,6 +411,9 @@ class PreambleThrottlerRequest { if (Throttler) Throttler->release(ID); } + PreambleThrottlerRequest(const PreambleThrottlerRequest &) = delete; + PreambleThrottlerRequest & + operator=(const PreambleThrottlerRequest &) = delete; private: PreambleThrottler::RequestID ID; @@ -621,7 +624,8 @@ class ASTWorker { AsyncTaskRunner *Tasks, Semaphore &Barrier, const TUScheduler::Options &Opts, ParsingCallbacks &Callbacks); ~ASTWorker(); - + ASTWorker(const ASTWorker &other) = delete; + ASTWorker &operator=(const ASTWorker &other) = delete; void update(ParseInputs Inputs, WantDiagnostics, bool ContentChanged); void runWithAST(llvm::StringRef Name, diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h index fb936d46bbcf7..d0da20310a8b2 100644 --- a/clang-tools-extra/clangd/TUScheduler.h +++ b/clang-tools-extra/clangd/TUScheduler.h @@ -242,6 +242,9 @@ class TUScheduler { std::unique_ptr ASTCallbacks = nullptr); ~TUScheduler(); + TUScheduler(const TUScheduler &other) = delete; + TUScheduler &operator=(const TUScheduler &other) = delete; + struct FileStats { std::size_t UsedBytesAST = 0; std::size_t UsedBytesPreamble = 0; diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 61fa66180376c..8d5ab2e491a40 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -121,31 +121,17 @@ void logIfOverflow(const SymbolLocation &Loc) { // Convert a SymbolLocation to LSP's Location. // TUPath is used to resolve the path of URI. -// FIXME: figure out a good home for it, and share the implementation with -// FindSymbols. std::optional toLSPLocation(const SymbolLocation &Loc, llvm::StringRef TUPath) { if (!Loc) return std::nullopt; - auto Uri = URI::parse(Loc.FileURI); - if (!Uri) { - elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError()); + auto LSPLoc = indexToLSPLocation(Loc, TUPath); + if (!LSPLoc) { + elog("{0}", LSPLoc.takeError()); return std::nullopt; } - auto U = URIForFile::fromURI(*Uri, TUPath); - if (!U) { - elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError()); - return std::nullopt; - } - - Location LSPLoc; - LSPLoc.uri = std::move(*U); - LSPLoc.range.start.line = Loc.Start.line(); - LSPLoc.range.start.character = Loc.Start.column(); - LSPLoc.range.end.line = Loc.End.line(); - LSPLoc.range.end.character = Loc.End.column(); logIfOverflow(Loc); - return LSPLoc; + return *LSPLoc; } SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) { @@ -1702,6 +1688,7 @@ declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) { HierarchyItem HI; HI.name = printName(Ctx, ND); + // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem? HI.kind = SK; HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()), sourceLocToPosition(SM, DeclRange->getEnd())}; @@ -1753,6 +1740,7 @@ static std::optional symbolToHierarchyItem(const Symbol &S, } HierarchyItem HI; HI.name = std::string(S.Name); + HI.detail = (S.Scope + S.Name).str(); HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind); HI.selectionRange = Loc->range; // FIXME: Populate 'range' correctly @@ -2319,6 +2307,65 @@ incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) { return Results; } +std::vector +outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) { + std::vector Results; + if (!Index || Item.data.empty()) + return Results; + auto ID = SymbolID::fromStr(Item.data); + if (!ID) { + elog("outgoingCalls failed to find symbol: {0}", ID.takeError()); + return Results; + } + // In this function, we find outgoing calls based on the index only. + ContainedRefsRequest Request; + Request.ID = *ID; + // Initially store the ranges in a map keyed by SymbolID of the callee. + // This allows us to group different calls to the same function + // into the same CallHierarchyOutgoingCall. + llvm::DenseMap> CallsOut; + // We can populate the ranges based on a refs request only. As we do so, we + // also accumulate the callee IDs into a lookup request. + LookupRequest CallsOutLookup; + Index->containedRefs(Request, [&](const auto &R) { + auto Loc = indexToLSPLocation(R.Location, Item.uri.file()); + if (!Loc) { + elog("outgoingCalls failed to convert location: {0}", Loc.takeError()); + return; + } + auto It = CallsOut.try_emplace(R.Symbol, std::vector{}).first; + It->second.push_back(Loc->range); + + CallsOutLookup.IDs.insert(R.Symbol); + }); + // Perform the lookup request and combine its results with CallsOut to + // get complete CallHierarchyOutgoingCall objects. + Index->lookup(CallsOutLookup, [&](const Symbol &Callee) { + // The containedRefs request should only return symbols which are + // function-like, i.e. symbols for which references to them can be "calls". + using SK = index::SymbolKind; + auto Kind = Callee.SymInfo.Kind; + assert(Kind == SK::Function || Kind == SK::InstanceMethod || + Kind == SK::ClassMethod || Kind == SK::StaticMethod || + Kind == SK::Constructor || Kind == SK::Destructor || + Kind == SK::ConversionFunction); + (void)Kind; + (void)SK::Function; + + auto It = CallsOut.find(Callee.ID); + assert(It != CallsOut.end()); + if (auto CHI = symbolToCallHierarchyItem(Callee, Item.uri.file())) + Results.push_back( + CallHierarchyOutgoingCall{std::move(*CHI), std::move(It->second)}); + }); + // Sort results by name of the callee. + llvm::sort(Results, [](const CallHierarchyOutgoingCall &A, + const CallHierarchyOutgoingCall &B) { + return A.to.name < B.to.name; + }); + return Results; +} + llvm::DenseSet getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD) { if (!FD->hasBody()) diff --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h index df91dd15303c1..247e52314c3f9 100644 --- a/clang-tools-extra/clangd/XRefs.h +++ b/clang-tools-extra/clangd/XRefs.h @@ -150,6 +150,9 @@ prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath); std::vector incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index); +std::vector +outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index); + /// Returns all decls that are referenced in the \p FD except local symbols. llvm::DenseSet getNonLocalDeclRefs(ParsedAST &AST, const FunctionDecl *FD); diff --git a/clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp b/clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp index bd32041bbe1fc..354e75d6e1559 100644 --- a/clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp +++ b/clang-tools-extra/clangd/benchmarks/IndexBenchmark.cpp @@ -24,12 +24,12 @@ namespace { std::unique_ptr buildMem() { return loadIndex(IndexFilename, clang::clangd::SymbolOrigin::Static, - /*UseDex=*/false); + /*UseDex=*/false, /*SupportContainedRefs=*/true); } std::unique_ptr buildDex() { return loadIndex(IndexFilename, clang::clangd::SymbolOrigin::Static, - /*UseDex=*/true); + /*UseDex=*/true, /*SupportContainedRefs=*/true); } // Reads JSON array of serialized FuzzyFindRequest's from user-provided file. diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp index 5cde4937fee78..496d1455def4b 100644 --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -96,7 +96,7 @@ BackgroundIndex::BackgroundIndex( : SwapIndex(std::make_unique()), TFS(TFS), CDB(CDB), IndexingPriority(Opts.IndexingPriority), ContextProvider(std::move(Opts.ContextProvider)), - IndexedSymbols(IndexContents::All), + IndexedSymbols(IndexContents::All, Opts.SupportContainedRefs), Rebuilder(this, &IndexedSymbols, Opts.ThreadPoolSize), IndexStorageFactory(std::move(IndexStorageFactory)), Queue(std::move(Opts.OnProgress)), diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h index 0d719ffdb957e..448e911201575 100644 --- a/clang-tools-extra/clangd/index/Background.h +++ b/clang-tools-extra/clangd/index/Background.h @@ -145,6 +145,9 @@ class BackgroundIndex : public SwapIndex { // file. Called with the empty string for other tasks. // (When called, the context from BackgroundIndex construction is active). std::function ContextProvider = nullptr; + // Whether the index needs to support the containedRefs() operation. + // May use extra memory. + bool SupportContainedRefs = true; }; /// Creates a new background index and starts its threads. diff --git a/clang-tools-extra/clangd/index/BackgroundRebuild.cpp b/clang-tools-extra/clangd/index/BackgroundRebuild.cpp index 79383be012f83..4dc2d3b1d059b 100644 --- a/clang-tools-extra/clangd/index/BackgroundRebuild.cpp +++ b/clang-tools-extra/clangd/index/BackgroundRebuild.cpp @@ -1,4 +1,4 @@ -//===-- BackgroundRebuild.cpp - when to rebuild thei background index -----===// +//===-- BackgroundRebuild.cpp - when to rebuild the background index ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp index eb9562d2b6bf8..aa573e312a756 100644 --- a/clang-tools-extra/clangd/index/FileIndex.cpp +++ b/clang-tools-extra/clangd/index/FileIndex.cpp @@ -239,8 +239,8 @@ SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST, /*CollectMainFileRefs=*/false); } -FileSymbols::FileSymbols(IndexContents IdxContents) - : IdxContents(IdxContents) {} +FileSymbols::FileSymbols(IndexContents IdxContents, bool SupportContainedRefs) + : IdxContents(IdxContents), SupportContainedRefs(SupportContainedRefs) {} void FileSymbols::update(llvm::StringRef Key, std::unique_ptr Symbols, @@ -395,7 +395,7 @@ FileSymbols::buildIndex(IndexType Type, DuplicateHandling DuplicateHandle, std::move(AllRelations), std::move(Files), IdxContents, std::make_tuple(std::move(SymbolSlabs), std::move(RefSlabs), std::move(RefsStorage), std::move(SymsStorage)), - StorageSize); + StorageSize, SupportContainedRefs); } llvm_unreachable("Unknown clangd::IndexType"); } @@ -419,11 +419,12 @@ void FileSymbols::profile(MemoryTree &MT) const { } } -FileIndex::FileIndex() +FileIndex::FileIndex(bool SupportContainedRefs) : MergedIndex(&MainFileIndex, &PreambleIndex), - PreambleSymbols(IndexContents::Symbols | IndexContents::Relations), + PreambleSymbols(IndexContents::Symbols | IndexContents::Relations, + SupportContainedRefs), PreambleIndex(std::make_unique()), - MainFileSymbols(IndexContents::All), + MainFileSymbols(IndexContents::All, SupportContainedRefs), MainFileIndex(std::make_unique()) {} void FileIndex::updatePreamble(IndexFileIn IF) { diff --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-tools-extra/clangd/index/FileIndex.h index 44f33e8fbcd51..8e88dc9712996 100644 --- a/clang-tools-extra/clangd/index/FileIndex.h +++ b/clang-tools-extra/clangd/index/FileIndex.h @@ -69,7 +69,7 @@ enum class DuplicateHandling { /// locking when we swap or obtain references to snapshots. class FileSymbols { public: - FileSymbols(IndexContents IdxContents); + FileSymbols(IndexContents IdxContents, bool SupportContainedRefs); /// Updates all slabs associated with the \p Key. /// If either is nullptr, corresponding data for \p Key will be removed. /// If CountReferences is true, \p Refs will be used for counting references @@ -91,6 +91,7 @@ class FileSymbols { private: IndexContents IdxContents; + bool SupportContainedRefs; struct RefSlabAndCountReferences { std::shared_ptr Slab; @@ -108,7 +109,7 @@ class FileSymbols { /// FIXME: Expose an interface to remove files that are closed. class FileIndex : public MergedIndex { public: - FileIndex(); + FileIndex(bool SupportContainedRefs); /// Update preamble symbols of file \p Path with all declarations in \p AST /// and macros in \p PP. diff --git a/clang-tools-extra/clangd/index/Index.cpp b/clang-tools-extra/clangd/index/Index.cpp index 7a0c23287db22..86dc6ed763344 100644 --- a/clang-tools-extra/clangd/index/Index.cpp +++ b/clang-tools-extra/clangd/index/Index.cpp @@ -66,6 +66,11 @@ bool SwapIndex::refs(const RefsRequest &R, llvm::function_ref CB) const { return snapshot()->refs(R, CB); } +bool SwapIndex::containedRefs( + const ContainedRefsRequest &R, + llvm::function_ref CB) const { + return snapshot()->containedRefs(R, CB); +} void SwapIndex::relations( const RelationsRequest &R, llvm::function_ref CB) const { diff --git a/clang-tools-extra/clangd/index/Index.h b/clang-tools-extra/clangd/index/Index.h index 047ce08e93e3a..a193b1a191216 100644 --- a/clang-tools-extra/clangd/index/Index.h +++ b/clang-tools-extra/clangd/index/Index.h @@ -77,6 +77,19 @@ struct RefsRequest { bool WantContainer = false; }; +struct ContainedRefsRequest { + /// Note that RefKind::Call just restricts the matched SymbolKind to + /// functions, not the form of the reference (e.g. address-of-function, + /// which can indicate an indirect call, should still be caught). + static const RefKind SupportedRefKinds = RefKind::Call; + + SymbolID ID; + /// If set, limit the number of refers returned from the index. The index may + /// choose to return less than this, e.g. it tries to avoid returning stale + /// results. + std::optional Limit; +}; + struct RelationsRequest { llvm::DenseSet Subjects; RelationKind Predicate; @@ -84,6 +97,14 @@ struct RelationsRequest { std::optional Limit; }; +struct ContainedRefsResult { + /// The source location where the symbol is named. + SymbolLocation Location; + RefKind Kind = RefKind::Unknown; + /// The ID of the symbol which is referred to + SymbolID Symbol; +}; + /// Describes what data is covered by an index. /// /// Indexes may contain symbols but not references from a file, etc. @@ -141,6 +162,17 @@ class SymbolIndex { virtual bool refs(const RefsRequest &Req, llvm::function_ref Callback) const = 0; + /// Find all symbols that are referenced by a symbol and apply + /// \p Callback on each result. + /// + /// Results should be returned in arbitrary order. + /// The returned result must be deep-copied if it's used outside Callback. + /// + /// Returns true if there will be more results (limited by Req.Limit); + virtual bool containedRefs( + const ContainedRefsRequest &Req, + llvm::function_ref Callback) const = 0; + /// Finds all relations (S, P, O) stored in the index such that S is among /// Req.Subjects and P is Req.Predicate, and invokes \p Callback for (S, O) in /// each. @@ -175,6 +207,9 @@ class SwapIndex : public SymbolIndex { llvm::function_ref) const override; bool refs(const RefsRequest &, llvm::function_ref) const override; + bool containedRefs( + const ContainedRefsRequest &, + llvm::function_ref) const override; void relations(const RelationsRequest &, llvm::function_ref) const override; diff --git a/clang-tools-extra/clangd/index/MemIndex.cpp b/clang-tools-extra/clangd/index/MemIndex.cpp index 2665d46b97d83..9c9d3942bdee6 100644 --- a/clang-tools-extra/clangd/index/MemIndex.cpp +++ b/clang-tools-extra/clangd/index/MemIndex.cpp @@ -9,6 +9,7 @@ #include "MemIndex.h" #include "FuzzyMatch.h" #include "Quality.h" +#include "index/Index.h" #include "support/Trace.h" namespace clang { @@ -85,6 +86,25 @@ bool MemIndex::refs(const RefsRequest &Req, return false; // We reported all refs. } +bool MemIndex::containedRefs( + const ContainedRefsRequest &Req, + llvm::function_ref Callback) const { + trace::Span Tracer("MemIndex refersTo"); + uint32_t Remaining = Req.Limit.value_or(std::numeric_limits::max()); + for (const auto &Pair : Refs) { + for (const auto &R : Pair.second) { + if (!static_cast(ContainedRefsRequest::SupportedRefKinds & R.Kind) || + Req.ID != R.Container) + continue; + if (Remaining == 0) + return true; // More refs were available. + --Remaining; + Callback({R.Location, R.Kind, Pair.first}); + } + } + return false; // We reported all refs. +} + void MemIndex::relations( const RelationsRequest &Req, llvm::function_ref Callback) const { diff --git a/clang-tools-extra/clangd/index/MemIndex.h b/clang-tools-extra/clangd/index/MemIndex.h index fba2c1a7120a2..fb1052b0c7ca8 100644 --- a/clang-tools-extra/clangd/index/MemIndex.h +++ b/clang-tools-extra/clangd/index/MemIndex.h @@ -72,6 +72,10 @@ class MemIndex : public SymbolIndex { bool refs(const RefsRequest &Req, llvm::function_ref Callback) const override; + bool containedRefs(const ContainedRefsRequest &Req, + llvm::function_ref + Callback) const override; + void relations(const RelationsRequest &Req, llvm::function_ref Callback) const override; @@ -93,7 +97,7 @@ class MemIndex : public SymbolIndex { // Set of files which were used during this index build. llvm::StringSet<> Files; // Contents of the index (symbols, references, etc.) - IndexContents IdxContents; + IndexContents IdxContents = IndexContents::None; std::shared_ptr KeepAlive; // poor man's move-only std::any // Size of memory retained by KeepAlive. size_t BackingDataSize = 0; diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp index 8221d4b1f4440..aecca38a885b6 100644 --- a/clang-tools-extra/clangd/index/Merge.cpp +++ b/clang-tools-extra/clangd/index/Merge.cpp @@ -155,6 +155,40 @@ bool MergedIndex::refs(const RefsRequest &Req, return More || StaticHadMore; } +bool MergedIndex::containedRefs( + const ContainedRefsRequest &Req, + llvm::function_ref Callback) const { + trace::Span Tracer("MergedIndex refersTo"); + bool More = false; + uint32_t Remaining = Req.Limit.value_or(std::numeric_limits::max()); + // We don't want duplicated refs from the static/dynamic indexes, + // and we can't reliably deduplicate them because offsets may differ slightly. + // We consider the dynamic index authoritative and report all its refs, + // and only report static index refs from other files. + More |= Dynamic->containedRefs(Req, [&](const auto &O) { + Callback(O); + assert(Remaining != 0); + --Remaining; + }); + if (Remaining == 0 && More) + return More; + auto DynamicContainsFile = Dynamic->indexedFiles(); + // We return less than Req.Limit if static index returns more refs for dirty + // files. + bool StaticHadMore = Static->containedRefs(Req, [&](const auto &O) { + if ((DynamicContainsFile(O.Location.FileURI) & IndexContents::References) != + IndexContents::None) + return; // ignore refs that have been seen from dynamic index. + if (Remaining == 0) { + More = true; + return; + } + --Remaining; + Callback(O); + }); + return More || StaticHadMore; +} + llvm::unique_function MergedIndex::indexedFiles() const { return [DynamicContainsFile{Dynamic->indexedFiles()}, diff --git a/clang-tools-extra/clangd/index/Merge.h b/clang-tools-extra/clangd/index/Merge.h index b8a562b0df5d9..7441be6e57e85 100644 --- a/clang-tools-extra/clangd/index/Merge.h +++ b/clang-tools-extra/clangd/index/Merge.h @@ -38,6 +38,9 @@ class MergedIndex : public SymbolIndex { llvm::function_ref) const override; bool refs(const RefsRequest &, llvm::function_ref) const override; + bool containedRefs( + const ContainedRefsRequest &, + llvm::function_ref) const override; void relations(const RelationsRequest &, llvm::function_ref) const override; diff --git a/clang-tools-extra/clangd/index/ProjectAware.cpp b/clang-tools-extra/clangd/index/ProjectAware.cpp index 2c6f8273b35d0..9836f0130362a 100644 --- a/clang-tools-extra/clangd/index/ProjectAware.cpp +++ b/clang-tools-extra/clangd/index/ProjectAware.cpp @@ -35,6 +35,10 @@ class ProjectAwareIndex : public SymbolIndex { /// Query all indexes while prioritizing the associated one (if any). bool refs(const RefsRequest &Req, llvm::function_ref Callback) const override; + /// Query all indexes while prioritizing the associated one (if any). + bool containedRefs(const ContainedRefsRequest &Req, + llvm::function_ref + Callback) const override; /// Queries only the associates index when Req.RestrictForCodeCompletion is /// set, otherwise queries all. @@ -94,6 +98,15 @@ bool ProjectAwareIndex::refs( return false; } +bool ProjectAwareIndex::containedRefs( + const ContainedRefsRequest &Req, + llvm::function_ref Callback) const { + trace::Span Tracer("ProjectAwareIndex::refersTo"); + if (auto *Idx = getIndex()) + return Idx->containedRefs(Req, Callback); + return false; +} + bool ProjectAwareIndex::fuzzyFind( const FuzzyFindRequest &Req, llvm::function_ref Callback) const { diff --git a/clang-tools-extra/clangd/index/Ref.h b/clang-tools-extra/clangd/index/Ref.h index 6e383e2ade3d2..870f77f56e6cb 100644 --- a/clang-tools-extra/clangd/index/Ref.h +++ b/clang-tools-extra/clangd/index/Ref.h @@ -63,6 +63,9 @@ enum class RefKind : uint8_t { // ^ this references Foo, but does not explicitly spell out its name // }; Spelled = 1 << 3, + // A reference which is a call. Used as a filter for which references + // to store in data structures used for computing outgoing calls. + Call = 1 << 4, All = Declaration | Definition | Reference | Spelled, }; diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp index 72a4e8b007668..f03839599612c 100644 --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -457,7 +457,7 @@ readCompileCommand(Reader CmdReader, llvm::ArrayRef Strings) { // The current versioning scheme is simple - non-current versions are rejected. // If you make a breaking change, bump this version number to invalidate stored // data. Later we may want to support some backward compatibility. -constexpr static uint32_t Version = 19; +constexpr static uint32_t Version = 20; llvm::Expected readRIFF(llvm::StringRef Data, SymbolOrigin Origin) { @@ -704,7 +704,8 @@ llvm::Expected readIndexFile(llvm::StringRef Data, } std::unique_ptr loadIndex(llvm::StringRef SymbolFilename, - SymbolOrigin Origin, bool UseDex) { + SymbolOrigin Origin, bool UseDex, + bool SupportContainedRefs) { trace::Span OverallTracer("LoadIndex"); auto Buffer = llvm::MemoryBuffer::getFile(SymbolFilename); if (!Buffer) { @@ -735,10 +736,11 @@ std::unique_ptr loadIndex(llvm::StringRef SymbolFilename, size_t NumRelations = Relations.size(); trace::Span Tracer("BuildIndex"); - auto Index = UseDex ? dex::Dex::build(std::move(Symbols), std::move(Refs), - std::move(Relations)) - : MemIndex::build(std::move(Symbols), std::move(Refs), - std::move(Relations)); + auto Index = UseDex + ? dex::Dex::build(std::move(Symbols), std::move(Refs), + std::move(Relations), SupportContainedRefs) + : MemIndex::build(std::move(Symbols), std::move(Refs), + std::move(Relations)); vlog("Loaded {0} from {1} with estimated memory usage {2} bytes\n" " - number of symbols: {3}\n" " - number of refs: {4}\n" diff --git a/clang-tools-extra/clangd/index/Serialization.h b/clang-tools-extra/clangd/index/Serialization.h index b6890d63d2c38..bf8e036afcb6c 100644 --- a/clang-tools-extra/clangd/index/Serialization.h +++ b/clang-tools-extra/clangd/index/Serialization.h @@ -83,7 +83,8 @@ std::string toYAML(const Ref &); // Build an in-memory static index from an index file. // The size should be relatively small, so data can be managed in memory. std::unique_ptr loadIndex(llvm::StringRef Filename, - SymbolOrigin Origin, bool UseDex = true); + SymbolOrigin Origin, bool UseDex, + bool SupportContainedRefs); } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 91ae9d3003a97..81125dbb1aeaf 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -18,6 +18,7 @@ #include "clang-include-cleaner/Record.h" #include "clang-include-cleaner/Types.h" #include "index/CanonicalIncludes.h" +#include "index/Ref.h" #include "index/Relation.h" #include "index/Symbol.h" #include "index/SymbolID.h" @@ -660,7 +661,7 @@ bool SymbolCollector::handleDeclOccurrence( auto FileLoc = SM.getFileLoc(Loc); auto FID = SM.getFileID(FileLoc); if (Opts.RefsInHeaders || FID == SM.getMainFileID()) { - addRef(ID, SymbolRef{FileLoc, FID, Roles, + addRef(ID, SymbolRef{FileLoc, FID, Roles, index::getSymbolInfo(ND).Kind, getRefContainer(ASTNode.Parent, Opts), isSpelled(FileLoc, *ND)}); } @@ -774,8 +775,10 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name, // FIXME: Populate container information for macro references. // FIXME: All MacroRefs are marked as Spelled now, but this should be // checked. - addRef(ID, SymbolRef{Loc, SM.getFileID(Loc), Roles, /*Container=*/nullptr, - /*Spelled=*/true}); + addRef(ID, + SymbolRef{Loc, SM.getFileID(Loc), Roles, index::SymbolKind::Macro, + /*Container=*/nullptr, + /*Spelled=*/true}); } // Collect symbols. @@ -1166,6 +1169,14 @@ bool SymbolCollector::shouldIndexFile(FileID FID) { return I.first->second; } +static bool refIsCall(index::SymbolKind Kind) { + using SK = index::SymbolKind; + return Kind == SK::Function || Kind == SK::InstanceMethod || + Kind == SK::ClassMethod || Kind == SK::StaticMethod || + Kind == SK::Constructor || Kind == SK::Destructor || + Kind == SK::ConversionFunction; +} + void SymbolCollector::addRef(SymbolID ID, const SymbolRef &SR) { const auto &SM = ASTCtx->getSourceManager(); // FIXME: use the result to filter out references. @@ -1177,6 +1188,9 @@ void SymbolCollector::addRef(SymbolID ID, const SymbolRef &SR) { R.Location.End = Range.second; R.Location.FileURI = HeaderFileURIs->toURI(*FE).c_str(); R.Kind = toRefKind(SR.Roles, SR.Spelled); + if (refIsCall(SR.Kind)) { + R.Kind |= RefKind::Call; + } R.Container = getSymbolIDCached(SR.Container); Refs.insert(ID, R); } diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h index 6ff7a0145ff87..e9eb27fd0f664 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -209,6 +209,7 @@ class SymbolCollector : public index::IndexDataConsumer { SourceLocation Loc; FileID FID; index::SymbolRoleSet Roles; + index::SymbolKind Kind; const Decl *Container; bool Spelled; }; diff --git a/clang-tools-extra/clangd/index/dex/Dex.cpp b/clang-tools-extra/clangd/index/dex/Dex.cpp index b7d3063e19b49..5643ba0c5e4ce 100644 --- a/clang-tools-extra/clangd/index/dex/Dex.cpp +++ b/clang-tools-extra/clangd/index/dex/Dex.cpp @@ -33,13 +33,14 @@ namespace clangd { namespace dex { std::unique_ptr Dex::build(SymbolSlab Symbols, RefSlab Refs, - RelationSlab Rels) { + RelationSlab Rels, + bool SupportContainedRefs) { auto Size = Symbols.bytes() + Refs.bytes(); // There is no need to include "Rels" in Data because the relations are self- // contained, without references into a backing store. auto Data = std::make_pair(std::move(Symbols), std::move(Refs)); return std::make_unique(Data.first, Data.second, Rels, std::move(Data), - Size); + Size, SupportContainedRefs); } namespace { @@ -120,7 +121,7 @@ class IndexBuilder { } // namespace -void Dex::buildIndex() { +void Dex::buildIndex(bool SupportContainedRefs) { this->Corpus = dex::Corpus(Symbols.size()); std::vector> ScoredSymbols(Symbols.size()); @@ -147,6 +148,20 @@ void Dex::buildIndex() { for (DocID SymbolRank = 0; SymbolRank < Symbols.size(); ++SymbolRank) Builder.add(*Symbols[SymbolRank], SymbolRank); InvertedIndex = std::move(Builder).build(); + + // If the containedRefs() operation is supported, build the RevRefs + // data structure used to implement it. + if (!SupportContainedRefs) + return; + for (const auto &[ID, RefList] : Refs) + for (const auto &R : RefList) + if ((R.Kind & ContainedRefsRequest::SupportedRefKinds) != + RefKind::Unknown) + RevRefs.emplace_back(R, ID); + // Sort by container ID so we can use binary search for lookup. + llvm::sort(RevRefs, [](const RevRef &A, const RevRef &B) { + return A.ref().Container < B.ref().Container; + }); } std::unique_ptr Dex::iterator(const Token &Tok) const { @@ -314,6 +329,36 @@ bool Dex::refs(const RefsRequest &Req, return false; // We reported all refs. } +llvm::iterator_range::const_iterator> +Dex::lookupRevRefs(const SymbolID &Container) const { + // equal_range() requires an element of the same type as the elements of the + // range, so construct a dummy RevRef with the container of interest. + Ref QueryRef; + QueryRef.Container = Container; + RevRef Query(QueryRef, SymbolID{}); + + auto ItPair = std::equal_range(RevRefs.cbegin(), RevRefs.cend(), Query, + [](const RevRef &A, const RevRef &B) { + return A.ref().Container < B.ref().Container; + }); + return {ItPair.first, ItPair.second}; +} + +bool Dex::containedRefs( + const ContainedRefsRequest &Req, + llvm::function_ref Callback) const { + trace::Span Tracer("Dex reversed refs"); + uint32_t Remaining = Req.Limit.value_or(std::numeric_limits::max()); + for (const auto &Rev : lookupRevRefs(Req.ID)) { + // RevRefs are already filtered to ContainedRefsRequest::SupportedRefKinds + if (Remaining == 0) + return true; // More refs were available. + --Remaining; + Callback(Rev.containedRefsResult()); + } + return false; // We reported all refs. +} + void Dex::relations( const RelationsRequest &Req, llvm::function_ref Callback) const { @@ -350,6 +395,7 @@ size_t Dex::estimateMemoryUsage() const { for (const auto &TokenToPostingList : InvertedIndex) Bytes += TokenToPostingList.second.bytes(); Bytes += Refs.getMemorySize(); + Bytes += RevRefs.size() * sizeof(RevRef); Bytes += Relations.getMemorySize(); return Bytes + BackingDataSize; } diff --git a/clang-tools-extra/clangd/index/dex/Dex.h b/clang-tools-extra/clangd/index/dex/Dex.h index 69e161d51135b..502f597d81ef0 100644 --- a/clang-tools-extra/clangd/index/dex/Dex.h +++ b/clang-tools-extra/clangd/index/dex/Dex.h @@ -36,7 +36,8 @@ class Dex : public SymbolIndex { public: // All data must outlive this index. template - Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations) + Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations, + bool SupportContainedRefs) : Corpus(0) { for (auto &&Sym : Symbols) this->Symbols.push_back(&Sym); @@ -46,15 +47,15 @@ class Dex : public SymbolIndex { this->Relations[std::make_pair(Rel.Subject, static_cast(Rel.Predicate))] .push_back(Rel.Object); - buildIndex(); + buildIndex(SupportContainedRefs); } // Symbols and Refs are owned by BackingData, Index takes ownership. template Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations, - Payload &&BackingData, size_t BackingDataSize) + Payload &&BackingData, size_t BackingDataSize, bool SupportContainedRefs) : Dex(std::forward(Symbols), std::forward(Refs), - std::forward(Relations)) { + std::forward(Relations), SupportContainedRefs) { KeepAlive = std::shared_ptr( std::make_shared(std::move(BackingData)), nullptr); this->BackingDataSize = BackingDataSize; @@ -64,16 +65,18 @@ class Dex : public SymbolIndex { typename FileRange, typename Payload> Dex(SymbolRange &&Symbols, RefsRange &&Refs, RelationsRange &&Relations, FileRange &&Files, IndexContents IdxContents, Payload &&BackingData, - size_t BackingDataSize) + size_t BackingDataSize, bool SupportContainedRefs) : Dex(std::forward(Symbols), std::forward(Refs), std::forward(Relations), - std::forward(BackingData), BackingDataSize) { + std::forward(BackingData), BackingDataSize, + SupportContainedRefs) { this->Files = std::forward(Files); this->IdxContents = IdxContents; } /// Builds an index from slabs. The index takes ownership of the slab. - static std::unique_ptr build(SymbolSlab, RefSlab, RelationSlab); + static std::unique_ptr build(SymbolSlab, RefSlab, RelationSlab, + bool SupportContainedRefs); bool fuzzyFind(const FuzzyFindRequest &Req, @@ -85,6 +88,10 @@ class Dex : public SymbolIndex { bool refs(const RefsRequest &Req, llvm::function_ref Callback) const override; + bool containedRefs(const ContainedRefsRequest &Req, + llvm::function_ref + Callback) const override; + void relations(const RelationsRequest &Req, llvm::function_ref Callback) const override; @@ -95,7 +102,22 @@ class Dex : public SymbolIndex { size_t estimateMemoryUsage() const override; private: - void buildIndex(); + class RevRef { + const Ref *Reference; + SymbolID Target; + + public: + RevRef(const Ref &Reference, SymbolID Target) + : Reference(&Reference), Target(Target) {} + const Ref &ref() const { return *Reference; } + ContainedRefsResult containedRefsResult() const { + return {ref().Location, ref().Kind, Target}; + } + }; + + void buildIndex(bool EnableOutgoingCalls); + llvm::iterator_range::const_iterator> + lookupRevRefs(const SymbolID &Container) const; std::unique_ptr iterator(const Token &Tok) const; std::unique_ptr createFileProximityIterator(llvm::ArrayRef ProximityPaths) const; @@ -116,6 +138,7 @@ class Dex : public SymbolIndex { llvm::DenseMap InvertedIndex; dex::Corpus Corpus; llvm::DenseMap> Refs; + std::vector RevRefs; // sorted by container ID static_assert(sizeof(RelationKind) == sizeof(uint8_t), "RelationKind should be of same size as a uint8_t"); llvm::DenseMap, std::vector> Relations; @@ -123,7 +146,9 @@ class Dex : public SymbolIndex { // Set of files which were used during this index build. llvm::StringSet<> Files; // Contents of the index (symbols, references, etc.) - IndexContents IdxContents; + // This is only populated if `Files` is, which applies to some but not all + // consumers of this class. + IndexContents IdxContents = IndexContents::None; // Size of memory retained by KeepAlive. size_t BackingDataSize = 0; }; diff --git a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp index cea59ae409914..f185808ae1544 100644 --- a/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp +++ b/clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp @@ -375,7 +375,8 @@ std::unique_ptr openIndex(llvm::StringRef Index) { return Index.starts_with("remote:") ? remote::getClient(Index.drop_front(strlen("remote:")), ProjectRoot) - : loadIndex(Index, SymbolOrigin::Static, /*UseDex=*/true); + : loadIndex(Index, SymbolOrigin::Static, /*UseDex=*/true, + /*SupportContainedRefs=*/true); } bool runCommand(std::string Request, const SymbolIndex &Index) { diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp index 391da3916259c..79b827126b4ef 100644 --- a/clang-tools-extra/clangd/index/remote/Client.cpp +++ b/clang-tools-extra/clangd/index/remote/Client.cpp @@ -146,6 +146,13 @@ class IndexClient : public clangd::SymbolIndex { return streamRPC(Request, &remote::v1::SymbolIndex::Stub::Refs, Callback); } + bool containedRefs(const clangd::ContainedRefsRequest &Request, + llvm::function_ref + Callback) const override { + return streamRPC(Request, &remote::v1::SymbolIndex::Stub::ContainedRefs, + Callback); + } + void relations(const clangd::RelationsRequest &Request, llvm::function_ref diff --git a/clang-tools-extra/clangd/index/remote/Index.proto b/clang-tools-extra/clangd/index/remote/Index.proto index 3072299d8f345..3e39724e32086 100644 --- a/clang-tools-extra/clangd/index/remote/Index.proto +++ b/clang-tools-extra/clangd/index/remote/Index.proto @@ -131,3 +131,21 @@ message Relation { optional string subject_id = 1; optional Symbol object = 2; } + +message ContainedRefsRequest { + optional string id = 1; + optional uint32 limit = 2; +} + +message ContainedRefsReply { + oneof kind { + ContainedRef stream_result = 1; + FinalResult final_result = 2; + } +} + +message ContainedRef { + optional SymbolLocation location = 1; + optional uint32 kind = 2; + optional string symbol = 3; +} diff --git a/clang-tools-extra/clangd/index/remote/Service.proto b/clang-tools-extra/clangd/index/remote/Service.proto index 7c7efa530200d..43023321cb9e1 100644 --- a/clang-tools-extra/clangd/index/remote/Service.proto +++ b/clang-tools-extra/clangd/index/remote/Service.proto @@ -21,5 +21,7 @@ service SymbolIndex { rpc Refs(RefsRequest) returns (stream RefsReply) {} + rpc ContainedRefs(ContainedRefsRequest) returns (stream ContainedRefsReply) {} + rpc Relations(RelationsRequest) returns (stream RelationsReply) {} } diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp index 7e31ada18a657..d8d3b64a5ac18 100644 --- a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp +++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.cpp @@ -126,6 +126,20 @@ Marshaller::fromProtobuf(const RefsRequest *Message) { return Req; } +llvm::Expected +Marshaller::fromProtobuf(const ContainedRefsRequest *Message) { + clangd::ContainedRefsRequest Req; + if (!Message->has_id()) + return error("ContainedRefsRequest requires an id."); + auto ID = SymbolID::fromStr(Message->id()); + if (!ID) + return ID.takeError(); + Req.ID = *ID; + if (Message->has_limit()) + Req.Limit = Message->limit(); + return Req; +} + llvm::Expected Marshaller::fromProtobuf(const RelationsRequest *Message) { clangd::RelationsRequest Req; @@ -192,6 +206,27 @@ llvm::Expected Marshaller::fromProtobuf(const Ref &Message) { return Result; } +llvm::Expected +Marshaller::fromProtobuf(const ContainedRef &Message) { + clangd::ContainedRefsResult Result; + if (!Message.has_location()) + return error("ContainedRef must have a location."); + if (!Message.has_kind()) + return error("ContainedRef must have a kind."); + if (!Message.has_symbol()) + return error("ContainedRef must have a symbol."); + auto Location = fromProtobuf(Message.location()); + if (!Location) + return Location.takeError(); + Result.Location = *Location; + Result.Kind = static_cast(Message.kind()); + auto Symbol = SymbolID::fromStr(Message.symbol()); + if (!Symbol) + return Symbol.takeError(); + Result.Symbol = *Symbol; + return Result; +} + llvm::Expected> Marshaller::fromProtobuf(const Relation &Message) { auto SubjectID = SymbolID::fromStr(Message.subject_id()); @@ -244,6 +279,15 @@ RefsRequest Marshaller::toProtobuf(const clangd::RefsRequest &From) { return RPCRequest; } +ContainedRefsRequest +Marshaller::toProtobuf(const clangd::ContainedRefsRequest &From) { + ContainedRefsRequest RPCRequest; + RPCRequest.set_id(From.ID.str()); + if (From.Limit) + RPCRequest.set_limit(*From.Limit); + return RPCRequest; +} + RelationsRequest Marshaller::toProtobuf(const clangd::RelationsRequest &From) { RelationsRequest RPCRequest; for (const auto &ID : From.Subjects) @@ -299,6 +343,18 @@ llvm::Expected Marshaller::toProtobuf(const clangd::Ref &From) { return Result; } +llvm::Expected +Marshaller::toProtobuf(const clangd::ContainedRefsResult &From) { + ContainedRef Result; + auto Location = toProtobuf(From.Location); + if (!Location) + return Location.takeError(); + *Result.mutable_location() = *Location; + Result.set_kind(static_cast(From.Kind)); + *Result.mutable_symbol() = From.Symbol.str(); + return Result; +} + llvm::Expected Marshaller::toProtobuf(const clangd::SymbolID &Subject, const clangd::Symbol &Object) { Relation Result; diff --git a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h index e827b4c155a20..5bee9205aef58 100644 --- a/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h +++ b/clang-tools-extra/clangd/index/remote/marshalling/Marshalling.h @@ -40,6 +40,8 @@ class Marshaller { llvm::Expected fromProtobuf(const Symbol &Message); llvm::Expected fromProtobuf(const Ref &Message); + llvm::Expected + fromProtobuf(const ContainedRef &Message); llvm::Expected> fromProtobuf(const Relation &Message); @@ -48,6 +50,8 @@ class Marshaller { llvm::Expected fromProtobuf(const FuzzyFindRequest *Message); llvm::Expected fromProtobuf(const RefsRequest *Message); + llvm::Expected + fromProtobuf(const ContainedRefsRequest *Message); llvm::Expected fromProtobuf(const RelationsRequest *Message); @@ -58,10 +62,13 @@ class Marshaller { LookupRequest toProtobuf(const clangd::LookupRequest &From); FuzzyFindRequest toProtobuf(const clangd::FuzzyFindRequest &From); RefsRequest toProtobuf(const clangd::RefsRequest &From); + ContainedRefsRequest toProtobuf(const clangd::ContainedRefsRequest &From); RelationsRequest toProtobuf(const clangd::RelationsRequest &From); llvm::Expected toProtobuf(const clangd::Symbol &From); llvm::Expected toProtobuf(const clangd::Ref &From); + llvm::Expected + toProtobuf(const clangd::ContainedRefsResult &From); llvm::Expected toProtobuf(const clangd::SymbolID &Subject, const clangd::Symbol &Object); diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp index 52fca53260a16..890b6c27ed928 100644 --- a/clang-tools-extra/clangd/index/remote/server/Server.cpp +++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp @@ -258,6 +258,53 @@ class RemoteIndexServer final : public v1::SymbolIndex::Service { return grpc::Status::OK; } + grpc::Status + ContainedRefs(grpc::ServerContext *Context, + const ContainedRefsRequest *Request, + grpc::ServerWriter *Reply) override { + auto StartTime = stopwatch::now(); + WithContextValue WithRequestContext(CurrentRequest, Context); + logRequest(*Request); + trace::Span Tracer("ContainedRefsRequest"); + auto Req = ProtobufMarshaller->fromProtobuf(Request); + if (!Req) { + elog("Can not parse ContainedRefsRequest from protobuf: {0}", + Req.takeError()); + return grpc::Status::CANCELLED; + } + if (!Req->Limit || *Req->Limit > LimitResults) { + log("[public] Limiting result size for ContainedRefs request from {0} to " + "{1}.", + Req->Limit, LimitResults); + Req->Limit = LimitResults; + } + unsigned Sent = 0; + unsigned FailedToSend = 0; + bool HasMore = + Index.containedRefs(*Req, [&](const clangd::ContainedRefsResult &Item) { + auto SerializedItem = ProtobufMarshaller->toProtobuf(Item); + if (!SerializedItem) { + elog("Unable to convert ContainedRefsResult to protobuf: {0}", + SerializedItem.takeError()); + ++FailedToSend; + return; + } + ContainedRefsReply NextMessage; + *NextMessage.mutable_stream_result() = *SerializedItem; + logResponse(NextMessage); + Reply->Write(NextMessage); + ++Sent; + }); + ContainedRefsReply LastMessage; + LastMessage.mutable_final_result()->set_has_more(HasMore); + logResponse(LastMessage); + Reply->Write(LastMessage); + SPAN_ATTACH(Tracer, "Sent", Sent); + SPAN_ATTACH(Tracer, "Failed to send", FailedToSend); + logRequestSummary("v1/ContainedRefs", Sent, StartTime); + return grpc::Status::OK; + } + grpc::Status Relations(grpc::ServerContext *Context, const RelationsRequest *Request, grpc::ServerWriter *Reply) override { @@ -396,7 +443,8 @@ void hotReload(clangd::SwapIndex &Index, llvm::StringRef IndexPath, LastStatus.getLastModificationTime(), Status->getLastModificationTime()); LastStatus = *Status; std::unique_ptr NewIndex = - loadIndex(IndexPath, SymbolOrigin::Static); + loadIndex(IndexPath, SymbolOrigin::Static, /*UseDex=*/true, + /*SupportContainedRefs=*/true); if (!NewIndex) { elog("Failed to load new index. Old index will be served."); return; @@ -532,8 +580,9 @@ int main(int argc, char *argv[]) { return Status.getError().value(); } - auto SymIndex = - clang::clangd::loadIndex(IndexPath, clang::clangd::SymbolOrigin::Static); + auto SymIndex = clang::clangd::loadIndex( + IndexPath, clang::clangd::SymbolOrigin::Static, /*UseDex=*/true, + /*SupportContainedRefs=*/true); if (!SymIndex) { llvm::errs() << "Failed to open the index.\n"; return -1; diff --git a/clang-tools-extra/clangd/support/DirectiveTree.cpp b/clang-tools-extra/clangd/support/DirectiveTree.cpp index d25da111681af..7ea08add7a107 100644 --- a/clang-tools-extra/clangd/support/DirectiveTree.cpp +++ b/clang-tools-extra/clangd/support/DirectiveTree.cpp @@ -328,6 +328,9 @@ class Preprocessor { Preprocessor(const TokenStream &In, TokenStream &Out) : In(In), Out(Out) {} ~Preprocessor() { Out.finalize(); } + Preprocessor(const Preprocessor &other) = delete; + Preprocessor &operator=(const Preprocessor &other) = delete; + void walk(const DirectiveTree &T) { for (const auto &C : T.Chunks) std::visit(*this, C); diff --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx index 0c04df86ae1c6..6368e7145b1e4 100644 Binary files a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx and b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx differ diff --git a/clang-tools-extra/clangd/test/type-hierarchy-ext.test b/clang-tools-extra/clangd/test/type-hierarchy-ext.test index ddb9a014be0c7..8d1a5dc31da0f 100644 --- a/clang-tools-extra/clangd/test/type-hierarchy-ext.test +++ b/clang-tools-extra/clangd/test/type-hierarchy-ext.test @@ -12,6 +12,7 @@ # CHECK-NEXT: "data": { # CHECK-NEXT: "symbolID": "A6576FE083F2949A" # CHECK-NEXT: }, +# CHECK-NEXT: "detail": "Child3", # CHECK-NEXT: "kind": 23, # CHECK-NEXT: "name": "Child3", # CHECK-NEXT: "range": { @@ -153,6 +154,7 @@ # CHECK-NEXT: "data": { # CHECK-NEXT: "symbolID": "5705B382DFC77CBC" # CHECK-NEXT: }, +# CHECK-NEXT: "detail": "Child4", # CHECK-NEXT: "kind": 23, # CHECK-NEXT: "name": "Child4", # CHECK-NEXT: "range": { diff --git a/clang-tools-extra/clangd/test/type-hierarchy.test b/clang-tools-extra/clangd/test/type-hierarchy.test index 69751000a7c6c..a5f13ab13d0b3 100644 --- a/clang-tools-extra/clangd/test/type-hierarchy.test +++ b/clang-tools-extra/clangd/test/type-hierarchy.test @@ -62,6 +62,7 @@ # CHECK-NEXT: ], # CHECK-NEXT: "symbolID": "ECDC0C46D75120F4" # CHECK-NEXT: }, +# CHECK-NEXT: "detail": "Child1", # CHECK-NEXT: "kind": 23, # CHECK-NEXT: "name": "Child1", # CHECK-NEXT: "range": { @@ -112,6 +113,7 @@ # CHECK-NEXT: ], # CHECK-NEXT: "symbolID": "A6576FE083F2949A" # CHECK-NEXT: }, +# CHECK-NEXT: "detail": "Child3", # CHECK-NEXT: "kind": 23, # CHECK-NEXT: "name": "Child3", # CHECK-NEXT: "range": { diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp index bc2eaa77a66ee..df8d075e80596 100644 --- a/clang-tools-extra/clangd/tool/Check.cpp +++ b/clang-tools-extra/clangd/tool/Check.cpp @@ -163,7 +163,7 @@ class Checker { unsigned ErrCount = 0; Checker(llvm::StringRef File, const ClangdLSPServer::Options &Opts) - : File(File), Opts(Opts) {} + : File(File), Opts(Opts), Index(/*SupportContainedRefs=*/true) {} // Read compilation database and choose a compile command for the file. bool buildCommand(const ThreadsafeFS &TFS) { diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index cc061e2d93231..80a0653f8f740 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -604,7 +604,7 @@ const char TestScheme::TestDir[] = "/clangd-test"; std::unique_ptr loadExternalIndex(const Config::ExternalIndexSpec &External, - AsyncTaskRunner *Tasks) { + AsyncTaskRunner *Tasks, bool SupportContainedRefs) { static const trace::Metric RemoteIndexUsed("used_remote_index", trace::Metric::Value, "address"); switch (External.Kind) { @@ -620,8 +620,9 @@ loadExternalIndex(const Config::ExternalIndexSpec &External, External.Location); auto NewIndex = std::make_unique(std::make_unique()); auto IndexLoadTask = [File = External.Location, - PlaceHolder = NewIndex.get()] { - if (auto Idx = loadIndex(File, SymbolOrigin::Static, /*UseDex=*/true)) + PlaceHolder = NewIndex.get(), SupportContainedRefs] { + if (auto Idx = loadIndex(File, SymbolOrigin::Static, /*UseDex=*/true, + SupportContainedRefs)) PlaceHolder->reset(std::move(Idx)); }; if (Tasks) { @@ -909,7 +910,12 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.BackgroundIndexPriority = BackgroundIndexPriority; Opts.ReferencesLimit = ReferencesLimit; Opts.Rename.LimitFiles = RenameFileLimit; - auto PAI = createProjectAwareIndex(loadExternalIndex, Sync); + auto PAI = createProjectAwareIndex( + [SupportContainedRefs = Opts.EnableOutgoingCalls]( + const Config::ExternalIndexSpec &External, AsyncTaskRunner *Tasks) { + return loadExternalIndex(External, Tasks, SupportContainedRefs); + }, + Sync); Opts.StaticIndex = PAI.get(); Opts.AsyncThreadsCount = WorkerThreadsCount; Opts.MemoryCleanup = getMemoryCleanupFunction(); diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp index e51942462fbdf..ada14c9939318 100644 --- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp @@ -685,7 +685,8 @@ TEST_F(BackgroundIndexTest, Reindex) { class BackgroundIndexRebuilderTest : public testing::Test { protected: BackgroundIndexRebuilderTest() - : Source(IndexContents::All), Target(std::make_unique()), + : Source(IndexContents::All, /*SupportContainedRefs=*/true), + Target(std::make_unique()), Rebuilder(&Target, &Source, /*Threads=*/10) { // Prepare FileSymbols with TestSymbol in it, for checkRebuild. TestSymbol.ID = SymbolID("foo"); diff --git a/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp b/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp index 8821d3aad9c78..316b94305c9ae 100644 --- a/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp +++ b/clang-tools-extra/clangd/unittests/CallHierarchyTests.cpp @@ -44,17 +44,27 @@ using ::testing::UnorderedElementsAre; // Helpers for matching call hierarchy data structures. MATCHER_P(withName, N, "") { return arg.name == N; } +MATCHER_P(withDetail, N, "") { return arg.detail == N; } MATCHER_P(withSelectionRange, R, "") { return arg.selectionRange == R; } template ::testing::Matcher from(ItemMatcher M) { return Field(&CallHierarchyIncomingCall::from, M); } +template +::testing::Matcher to(ItemMatcher M) { + return Field(&CallHierarchyOutgoingCall::to, M); +} template -::testing::Matcher fromRanges(RangeMatchers... M) { +::testing::Matcher iFromRanges(RangeMatchers... M) { return Field(&CallHierarchyIncomingCall::fromRanges, UnorderedElementsAre(M...)); } +template +::testing::Matcher oFromRanges(RangeMatchers... M) { + return Field(&CallHierarchyOutgoingCall::fromRanges, + UnorderedElementsAre(M...)); +} TEST(CallHierarchy, IncomingOneFileCpp) { Annotations Source(R"cpp( @@ -79,21 +89,24 @@ TEST(CallHierarchy, IncomingOneFileCpp) { prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename)); ASSERT_THAT(Items, ElementsAre(withName("callee"))); auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); - ASSERT_THAT(IncomingLevel1, - ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Source.range("Callee"))))); + ASSERT_THAT( + IncomingLevel1, + ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))), + iFromRanges(Source.range("Callee"))))); auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get()); - ASSERT_THAT(IncomingLevel2, - ElementsAre(AllOf(from(withName("caller2")), - fromRanges(Source.range("Caller1A"), - Source.range("Caller1B"))), - AllOf(from(withName("caller3")), - fromRanges(Source.range("Caller1C"))))); + ASSERT_THAT( + IncomingLevel2, + ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))), + iFromRanges(Source.range("Caller1A"), + Source.range("Caller1B"))), + AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))), + iFromRanges(Source.range("Caller1C"))))); auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get()); - ASSERT_THAT(IncomingLevel3, - ElementsAre(AllOf(from(withName("caller3")), - fromRanges(Source.range("Caller2"))))); + ASSERT_THAT( + IncomingLevel3, + ElementsAre(AllOf(from(AllOf(withName("caller3"), withDetail("caller3"))), + iFromRanges(Source.range("Caller2"))))); auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get()); EXPECT_THAT(IncomingLevel4, IsEmpty()); @@ -125,20 +138,24 @@ TEST(CallHierarchy, IncomingOneFileObjC) { ASSERT_THAT(Items, ElementsAre(withName("callee"))); auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); ASSERT_THAT(IncomingLevel1, - ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Source.range("Callee"))))); + ElementsAre(AllOf(from(AllOf(withName("caller1"), + withDetail("MyClass::caller1"))), + iFromRanges(Source.range("Callee"))))); auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get()); ASSERT_THAT(IncomingLevel2, - ElementsAre(AllOf(from(withName("caller2")), - fromRanges(Source.range("Caller1A"), - Source.range("Caller1B"))), - AllOf(from(withName("caller3")), - fromRanges(Source.range("Caller1C"))))); + ElementsAre(AllOf(from(AllOf(withName("caller2"), + withDetail("MyClass::caller2"))), + iFromRanges(Source.range("Caller1A"), + Source.range("Caller1B"))), + AllOf(from(AllOf(withName("caller3"), + withDetail("MyClass::caller3"))), + iFromRanges(Source.range("Caller1C"))))); auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get()); ASSERT_THAT(IncomingLevel3, - ElementsAre(AllOf(from(withName("caller3")), - fromRanges(Source.range("Caller2"))))); + ElementsAre(AllOf(from(AllOf(withName("caller3"), + withDetail("MyClass::caller3"))), + iFromRanges(Source.range("Caller2"))))); auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get()); EXPECT_THAT(IncomingLevel4, IsEmpty()); @@ -167,14 +184,16 @@ TEST(CallHierarchy, MainFileOnlyRef) { prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename)); ASSERT_THAT(Items, ElementsAre(withName("callee"))); auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); - ASSERT_THAT(IncomingLevel1, - ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Source.range("Callee"))))); + ASSERT_THAT( + IncomingLevel1, + ElementsAre(AllOf(from(AllOf(withName("caller1"), withDetail("caller1"))), + iFromRanges(Source.range("Callee"))))); auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get()); - EXPECT_THAT(IncomingLevel2, - ElementsAre(AllOf(from(withName("caller2")), - fromRanges(Source.range("Caller1"))))); + EXPECT_THAT( + IncomingLevel2, + ElementsAre(AllOf(from(AllOf(withName("caller2"), withDetail("caller2"))), + iFromRanges(Source.range("Caller1"))))); } TEST(CallHierarchy, IncomingQualified) { @@ -200,14 +219,72 @@ TEST(CallHierarchy, IncomingQualified) { prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename)); ASSERT_THAT(Items, ElementsAre(withName("Waldo::find"))); auto Incoming = incomingCalls(Items[0], Index.get()); - EXPECT_THAT(Incoming, - ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Source.range("Caller1"))), - AllOf(from(withName("caller2")), - fromRanges(Source.range("Caller2"))))); + EXPECT_THAT( + Incoming, + ElementsAre( + AllOf(from(AllOf(withName("caller1"), withDetail("ns::caller1"))), + iFromRanges(Source.range("Caller1"))), + AllOf(from(AllOf(withName("caller2"), withDetail("ns::caller2"))), + iFromRanges(Source.range("Caller2"))))); } -TEST(CallHierarchy, IncomingMultiFileCpp) { +TEST(CallHierarchy, OutgoingOneFile) { + // Test outgoing call on the main file, with namespaces and methods + Annotations Source(R"cpp( + void callee(int); + namespace ns { + struct Foo { + void caller1(); + }; + void Foo::caller1() { + $Callee[[callee]](42); + } + } + namespace { + void caller2(ns::Foo& F) { + F.$Caller1A[[caller1]](); + F.$Caller1B[[caller1]](); + } + } + void call^er3(ns::Foo& F) { + F.$Caller1C[[caller1]](); + $Caller2[[caller2]](F); + } + )cpp"); + TestTU TU = TestTU::withCode(Source.code()); + auto AST = TU.build(); + auto Index = TU.index(); + + std::vector Items = + prepareCallHierarchy(AST, Source.point(), testPath(TU.Filename)); + ASSERT_THAT(Items, ElementsAre(withName("caller3"))); + auto OugoingLevel1 = outgoingCalls(Items[0], Index.get()); + ASSERT_THAT( + OugoingLevel1, + ElementsAre( + AllOf(to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))), + oFromRanges(Source.range("Caller1C"))), + AllOf(to(AllOf(withName("caller2"), withDetail("caller2"))), + oFromRanges(Source.range("Caller2"))))); + + auto OutgoingLevel2 = outgoingCalls(OugoingLevel1[1].to, Index.get()); + ASSERT_THAT( + OutgoingLevel2, + ElementsAre(AllOf( + to(AllOf(withName("caller1"), withDetail("ns::Foo::caller1"))), + oFromRanges(Source.range("Caller1A"), Source.range("Caller1B"))))); + + auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get()); + ASSERT_THAT( + OutgoingLevel3, + ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))), + oFromRanges(Source.range("Callee"))))); + + auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get()); + EXPECT_THAT(OutgoingLevel4, IsEmpty()); +} + +TEST(CallHierarchy, MultiFileCpp) { // The test uses a .hh suffix for header files to get clang // to parse them in C++ mode. .h files are parsed in C mode // by default, which causes problems because e.g. symbol @@ -221,32 +298,47 @@ TEST(CallHierarchy, IncomingMultiFileCpp) { void calle^e(int) {} )cpp"); Annotations Caller1H(R"cpp( - void caller1(); + namespace nsa { + void caller1(); + } )cpp"); Annotations Caller1C(R"cpp( #include "callee.hh" #include "caller1.hh" - void caller1() { - [[calle^e]](42); + namespace nsa { + void caller1() { + [[calle^e]](42); + } } )cpp"); Annotations Caller2H(R"cpp( - void caller2(); + namespace nsb { + void caller2(); + } )cpp"); Annotations Caller2C(R"cpp( #include "caller1.hh" #include "caller2.hh" - void caller2() { - $A[[caller1]](); - $B[[caller1]](); + namespace nsb { + void caller2() { + nsa::$A[[caller1]](); + nsa::$B[[caller1]](); + } + } + )cpp"); + Annotations Caller3H(R"cpp( + namespace nsa { + void call^er3(); } )cpp"); Annotations Caller3C(R"cpp( #include "caller1.hh" #include "caller2.hh" - void caller3() { - $Caller1[[caller1]](); - $Caller2[[caller2]](); + namespace nsa { + void call^er3() { + $Caller1[[caller1]](); + nsb::$Caller2[[caller2]](); + } } )cpp"); @@ -254,6 +346,7 @@ TEST(CallHierarchy, IncomingMultiFileCpp) { Workspace.addSource("callee.hh", CalleeH.code()); Workspace.addSource("caller1.hh", Caller1H.code()); Workspace.addSource("caller2.hh", Caller2H.code()); + Workspace.addSource("caller3.hh", Caller3H.code()); Workspace.addMainFile("callee.cc", CalleeC.code()); Workspace.addMainFile("caller1.cc", Caller1C.code()); Workspace.addMainFile("caller2.cc", Caller2C.code()); @@ -261,46 +354,84 @@ TEST(CallHierarchy, IncomingMultiFileCpp) { auto Index = Workspace.index(); - auto CheckCallHierarchy = [&](ParsedAST &AST, Position Pos, PathRef TUPath) { + auto CheckIncomingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) { std::vector Items = prepareCallHierarchy(AST, Pos, TUPath); ASSERT_THAT(Items, ElementsAre(withName("callee"))); auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); ASSERT_THAT(IncomingLevel1, - ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Caller1C.range())))); + ElementsAre(AllOf(from(AllOf(withName("caller1"), + withDetail("nsa::caller1"))), + iFromRanges(Caller1C.range())))); auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get()); ASSERT_THAT( IncomingLevel2, - ElementsAre(AllOf(from(withName("caller2")), - fromRanges(Caller2C.range("A"), Caller2C.range("B"))), - AllOf(from(withName("caller3")), - fromRanges(Caller3C.range("Caller1"))))); + ElementsAre( + AllOf(from(AllOf(withName("caller2"), withDetail("nsb::caller2"))), + iFromRanges(Caller2C.range("A"), Caller2C.range("B"))), + AllOf(from(AllOf(withName("caller3"), withDetail("nsa::caller3"))), + iFromRanges(Caller3C.range("Caller1"))))); auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get()); ASSERT_THAT(IncomingLevel3, - ElementsAre(AllOf(from(withName("caller3")), - fromRanges(Caller3C.range("Caller2"))))); + ElementsAre(AllOf(from(AllOf(withName("caller3"), + withDetail("nsa::caller3"))), + iFromRanges(Caller3C.range("Caller2"))))); auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get()); EXPECT_THAT(IncomingLevel4, IsEmpty()); }; + auto CheckOutgoingCalls = [&](ParsedAST &AST, Position Pos, PathRef TUPath) { + std::vector Items = + prepareCallHierarchy(AST, Pos, TUPath); + ASSERT_THAT(Items, ElementsAre(withName("caller3"))); + auto OutgoingLevel1 = outgoingCalls(Items[0], Index.get()); + ASSERT_THAT( + OutgoingLevel1, + ElementsAre( + AllOf(to(AllOf(withName("caller1"), withDetail("nsa::caller1"))), + oFromRanges(Caller3C.range("Caller1"))), + AllOf(to(AllOf(withName("caller2"), withDetail("nsb::caller2"))), + oFromRanges(Caller3C.range("Caller2"))))); + + auto OutgoingLevel2 = outgoingCalls(OutgoingLevel1[1].to, Index.get()); + ASSERT_THAT(OutgoingLevel2, + ElementsAre(AllOf( + to(AllOf(withName("caller1"), withDetail("nsa::caller1"))), + oFromRanges(Caller2C.range("A"), Caller2C.range("B"))))); + + auto OutgoingLevel3 = outgoingCalls(OutgoingLevel2[0].to, Index.get()); + ASSERT_THAT( + OutgoingLevel3, + ElementsAre(AllOf(to(AllOf(withName("callee"), withDetail("callee"))), + oFromRanges(Caller1C.range())))); + + auto OutgoingLevel4 = outgoingCalls(OutgoingLevel3[0].to, Index.get()); + EXPECT_THAT(OutgoingLevel4, IsEmpty()); + }; + // Check that invoking from a call site works. auto AST = Workspace.openFile("caller1.cc"); ASSERT_TRUE(bool(AST)); - CheckCallHierarchy(*AST, Caller1C.point(), testPath("caller1.cc")); + CheckIncomingCalls(*AST, Caller1C.point(), testPath("caller1.cc")); // Check that invoking from the declaration site works. AST = Workspace.openFile("callee.hh"); ASSERT_TRUE(bool(AST)); - CheckCallHierarchy(*AST, CalleeH.point(), testPath("callee.hh")); + CheckIncomingCalls(*AST, CalleeH.point(), testPath("callee.hh")); + AST = Workspace.openFile("caller3.hh"); + ASSERT_TRUE(bool(AST)); + CheckOutgoingCalls(*AST, Caller3H.point(), testPath("caller3.hh")); // Check that invoking from the definition site works. AST = Workspace.openFile("callee.cc"); ASSERT_TRUE(bool(AST)); - CheckCallHierarchy(*AST, CalleeC.point(), testPath("callee.cc")); + CheckIncomingCalls(*AST, CalleeC.point(), testPath("callee.cc")); + AST = Workspace.openFile("caller3.cc"); + ASSERT_TRUE(bool(AST)); + CheckOutgoingCalls(*AST, Caller3C.point(), testPath("caller3.cc")); } TEST(CallHierarchy, IncomingMultiFileObjC) { @@ -377,20 +508,20 @@ TEST(CallHierarchy, IncomingMultiFileObjC) { auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); ASSERT_THAT(IncomingLevel1, ElementsAre(AllOf(from(withName("caller1")), - fromRanges(Caller1C.range())))); + iFromRanges(Caller1C.range())))); auto IncomingLevel2 = incomingCalls(IncomingLevel1[0].from, Index.get()); - ASSERT_THAT( - IncomingLevel2, - ElementsAre(AllOf(from(withName("caller2")), - fromRanges(Caller2C.range("A"), Caller2C.range("B"))), - AllOf(from(withName("caller3")), - fromRanges(Caller3C.range("Caller1"))))); + ASSERT_THAT(IncomingLevel2, + ElementsAre(AllOf(from(withName("caller2")), + iFromRanges(Caller2C.range("A"), + Caller2C.range("B"))), + AllOf(from(withName("caller3")), + iFromRanges(Caller3C.range("Caller1"))))); auto IncomingLevel3 = incomingCalls(IncomingLevel2[0].from, Index.get()); ASSERT_THAT(IncomingLevel3, ElementsAre(AllOf(from(withName("caller3")), - fromRanges(Caller3C.range("Caller2"))))); + iFromRanges(Caller3C.range("Caller2"))))); auto IncomingLevel4 = incomingCalls(IncomingLevel3[0].from, Index.get()); EXPECT_THAT(IncomingLevel4, IsEmpty()); @@ -438,12 +569,12 @@ TEST(CallHierarchy, CallInLocalVarDecl) { ASSERT_THAT(Items, ElementsAre(withName("callee"))); auto Incoming = incomingCalls(Items[0], Index.get()); - ASSERT_THAT( - Incoming, - ElementsAre( - AllOf(from(withName("caller1")), fromRanges(Source.range("call1"))), - AllOf(from(withName("caller2")), fromRanges(Source.range("call2"))), - AllOf(from(withName("caller3")), fromRanges(Source.range("call3"))))); + ASSERT_THAT(Incoming, ElementsAre(AllOf(from(withName("caller1")), + iFromRanges(Source.range("call1"))), + AllOf(from(withName("caller2")), + iFromRanges(Source.range("call2"))), + AllOf(from(withName("caller3")), + iFromRanges(Source.range("call3"))))); } TEST(CallHierarchy, HierarchyOnField) { @@ -467,7 +598,7 @@ TEST(CallHierarchy, HierarchyOnField) { auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); ASSERT_THAT(IncomingLevel1, ElementsAre(AllOf(from(withName("caller")), - fromRanges(Source.range("Callee"))))); + iFromRanges(Source.range("Callee"))))); } TEST(CallHierarchy, HierarchyOnVar) { @@ -488,7 +619,7 @@ TEST(CallHierarchy, HierarchyOnVar) { auto IncomingLevel1 = incomingCalls(Items[0], Index.get()); ASSERT_THAT(IncomingLevel1, ElementsAre(AllOf(from(withName("caller")), - fromRanges(Source.range("Callee"))))); + iFromRanges(Source.range("Callee"))))); } TEST(CallHierarchy, CallInDifferentFileThanCaller) { @@ -517,7 +648,7 @@ TEST(CallHierarchy, CallInDifferentFileThanCaller) { // header. The protocol does not allow us to represent such calls, so we drop // them. (The call hierarchy item itself is kept.) EXPECT_THAT(Incoming, - ElementsAre(AllOf(from(withName("caller")), fromRanges()))); + ElementsAre(AllOf(from(withName("caller")), iFromRanges()))); } } // namespace diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index a89f499736226..3acacf496e77f 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1703,6 +1703,12 @@ class IndexRequestCollector : public SymbolIndex { return false; } + bool containedRefs( + const ContainedRefsRequest &, + llvm::function_ref) const override { + return false; + } + void relations(const RelationsRequest &, llvm::function_ref) const override {} diff --git a/clang-tools-extra/clangd/unittests/DexTests.cpp b/clang-tools-extra/clangd/unittests/DexTests.cpp index cafbfd324840c..ca8b81b5cb3c0 100644 --- a/clang-tools-extra/clangd/unittests/DexTests.cpp +++ b/clang-tools-extra/clangd/unittests/DexTests.cpp @@ -476,7 +476,7 @@ TEST(DexSearchTokens, SymbolPath) { TEST(Dex, Lookup) { auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); EXPECT_THAT(lookup(*I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc")); EXPECT_THAT(lookup(*I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}), UnorderedElementsAre("ns::abc", "ns::xyz")); @@ -489,7 +489,7 @@ TEST(Dex, FuzzyFind) { auto Index = Dex::build(generateSymbols({"ns::ABC", "ns::BCD", "::ABC", "ns::nested::ABC", "other::ABC", "other::A"}), - RefSlab(), RelationSlab()); + RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "ABC"; Req.Scopes = {"ns::"}; @@ -511,7 +511,8 @@ TEST(Dex, FuzzyFind) { } TEST(DexTest, DexLimitedNumMatches) { - auto I = Dex::build(generateNumSymbols(0, 100), RefSlab(), RelationSlab()); + auto I = + Dex::build(generateNumSymbols(0, 100), RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "5"; Req.AnyScope = true; @@ -526,7 +527,7 @@ TEST(DexTest, DexLimitedNumMatches) { TEST(DexTest, FuzzyMatch) { auto I = Dex::build( generateSymbols({"LaughingOutLoud", "LionPopulation", "LittleOldLady"}), - RefSlab(), RelationSlab()); + RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "lol"; Req.AnyScope = true; @@ -537,7 +538,7 @@ TEST(DexTest, FuzzyMatch) { TEST(DexTest, ShortQuery) { auto I = Dex::build(generateSymbols({"_OneTwoFourSix"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; bool Incomplete; @@ -580,7 +581,7 @@ TEST(DexTest, ShortQuery) { TEST(DexTest, MatchQualifiedNamesWithoutSpecificScope) { auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; Req.Query = "y"; @@ -589,7 +590,7 @@ TEST(DexTest, MatchQualifiedNamesWithoutSpecificScope) { TEST(DexTest, MatchQualifiedNamesWithGlobalScope) { auto I = Dex::build(generateSymbols({"a::y1", "b::y2", "y3"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {""}; @@ -599,7 +600,7 @@ TEST(DexTest, MatchQualifiedNamesWithGlobalScope) { TEST(DexTest, MatchQualifiedNamesWithOneScope) { auto I = Dex::build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}), - RefSlab(), RelationSlab()); + RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::"}; @@ -609,7 +610,7 @@ TEST(DexTest, MatchQualifiedNamesWithOneScope) { TEST(DexTest, MatchQualifiedNamesWithMultipleScopes) { auto I = Dex::build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}), - RefSlab(), RelationSlab()); + RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::", "b::"}; @@ -618,7 +619,7 @@ TEST(DexTest, MatchQualifiedNamesWithMultipleScopes) { TEST(DexTest, NoMatchNestedScopes) { auto I = Dex::build(generateSymbols({"a::y1", "a::b::y2"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "y"; Req.Scopes = {"a::"}; @@ -627,7 +628,7 @@ TEST(DexTest, NoMatchNestedScopes) { TEST(DexTest, WildcardScope) { auto I = Dex::build(generateSymbols({"a::y1", "a::b::y2", "c::y3"}), - RefSlab(), RelationSlab()); + RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; Req.Query = "y"; @@ -638,7 +639,7 @@ TEST(DexTest, WildcardScope) { TEST(DexTest, IgnoreCases) { auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.Query = "AB"; Req.Scopes = {"ns::"}; @@ -648,7 +649,7 @@ TEST(DexTest, IgnoreCases) { TEST(DexTest, UnknownPostingList) { // Regression test: we used to ignore unknown scopes and accept any symbol. auto I = Dex::build(generateSymbols({"ns::ABC", "ns::abc"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); FuzzyFindRequest Req; Req.Scopes = {"ns2::"}; EXPECT_THAT(match(*I, Req), UnorderedElementsAre()); @@ -656,7 +657,7 @@ TEST(DexTest, UnknownPostingList) { TEST(DexTest, Lookup) { auto I = Dex::build(generateSymbols({"ns::abc", "ns::xyz"}), RefSlab(), - RelationSlab()); + RelationSlab(), true); EXPECT_THAT(lookup(*I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc")); EXPECT_THAT(lookup(*I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}), UnorderedElementsAre("ns::abc", "ns::xyz")); @@ -671,7 +672,7 @@ TEST(DexTest, SymbolIndexOptionsFilter) { CodeCompletionSymbol.Flags = Symbol::SymbolFlag::IndexedForCodeCompletion; NonCodeCompletionSymbol.Flags = Symbol::SymbolFlag::None; std::vector Symbols{CodeCompletionSymbol, NonCodeCompletionSymbol}; - Dex I(Symbols, RefSlab(), RelationSlab()); + Dex I(Symbols, RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; Req.RestrictForCodeCompletion = false; @@ -687,7 +688,7 @@ TEST(DexTest, ProximityPathsBoosting) { CloseSymbol.CanonicalDeclaration.FileURI = "unittest:///a/b/c/d/e/f/file.h"; std::vector Symbols{CloseSymbol, RootSymbol}; - Dex I(Symbols, RefSlab(), RelationSlab()); + Dex I(Symbols, RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; @@ -726,7 +727,7 @@ TEST(DexTests, Refs) { Req.Filter = RefKind::Declaration | RefKind::Definition; std::vector Files; - EXPECT_FALSE(Dex(std::vector{Foo, Bar}, Refs, RelationSlab()) + EXPECT_FALSE(Dex(std::vector{Foo, Bar}, Refs, RelationSlab(), true) .refs(Req, [&](const Ref &R) { Files.push_back(R.Location.FileURI); })); @@ -734,7 +735,7 @@ TEST(DexTests, Refs) { Req.Limit = 1; Files.clear(); - EXPECT_TRUE(Dex(std::vector{Foo, Bar}, Refs, RelationSlab()) + EXPECT_TRUE(Dex(std::vector{Foo, Bar}, Refs, RelationSlab(), true) .refs(Req, [&](const Ref &R) { Files.push_back(R.Location.FileURI); })); @@ -751,7 +752,7 @@ TEST(DexTests, Relations) { std::vector Relations{{Parent.ID, RelationKind::BaseOf, Child1.ID}, {Parent.ID, RelationKind::BaseOf, Child2.ID}}; - Dex I{Symbols, RefSlab(), Relations}; + Dex I{Symbols, RefSlab(), Relations, true}; std::vector Results; RelationsRequest Req; @@ -770,7 +771,7 @@ TEST(DexIndex, IndexedFiles) { auto Data = std::make_pair(std::move(Symbols), std::move(Refs)); llvm::StringSet<> Files = {"unittest:///foo.cc", "unittest:///bar.cc"}; Dex I(std::move(Data.first), std::move(Data.second), RelationSlab(), - std::move(Files), IndexContents::All, std::move(Data), Size); + std::move(Files), IndexContents::All, std::move(Data), Size, true); auto ContainsFile = I.indexedFiles(); EXPECT_EQ(ContainsFile("unittest:///foo.cc"), IndexContents::All); EXPECT_EQ(ContainsFile("unittest:///bar.cc"), IndexContents::All); @@ -784,7 +785,7 @@ TEST(DexTest, PreferredTypesBoosting) { Sym2.Type = "T2"; std::vector Symbols{Sym1, Sym2}; - Dex I(Symbols, RefSlab(), RelationSlab()); + Dex I(Symbols, RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; @@ -820,7 +821,8 @@ TEST(DexTest, TemplateSpecialization) { index::SymbolProperty::TemplatePartialSpecialization); B.insert(S); - auto I = dex::Dex::build(std::move(B).build(), RefSlab(), RelationSlab()); + auto I = + dex::Dex::build(std::move(B).build(), RefSlab(), RelationSlab(), true); FuzzyFindRequest Req; Req.AnyScope = true; diff --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp index 9f713564b2c01..a92142fbcd7c4 100644 --- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp @@ -104,7 +104,7 @@ std::unique_ptr relSlab(llvm::ArrayRef Rels) { } TEST(FileSymbolsTest, UpdateAndGet) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); EXPECT_THAT(runFuzzyFind(*FS.buildIndex(IndexType::Light), ""), IsEmpty()); FS.update("f1", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cc"), nullptr, @@ -116,7 +116,7 @@ TEST(FileSymbolsTest, UpdateAndGet) { } TEST(FileSymbolsTest, Overlap) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); FS.update("f1", numSlab(1, 3), nullptr, nullptr, false); FS.update("f2", numSlab(3, 5), nullptr, nullptr, false); for (auto Type : {IndexType::Light, IndexType::Heavy}) @@ -126,7 +126,7 @@ TEST(FileSymbolsTest, Overlap) { } TEST(FileSymbolsTest, MergeOverlap) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); auto OneSymboSlab = [](Symbol Sym) { SymbolSlab::Builder S; S.insert(Sym); @@ -147,7 +147,7 @@ TEST(FileSymbolsTest, MergeOverlap) { } TEST(FileSymbolsTest, SnapshotAliveAfterRemove) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); SymbolID ID("1"); FS.update("f1", numSlab(1, 3), refSlab(ID, "f1.cc"), nullptr, false); @@ -180,14 +180,14 @@ void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) { } TEST(FileIndexTest, CustomizedURIScheme) { - FileIndex M; + FileIndex M(true); update(M, "f", "class string {};"); EXPECT_THAT(runFuzzyFind(M, ""), ElementsAre(declURI("unittest:///f.h"))); } TEST(FileIndexTest, IndexAST) { - FileIndex M; + FileIndex M(true); update(M, "f1", "namespace ns { void f() {} class X {}; }"); FuzzyFindRequest Req; @@ -198,7 +198,7 @@ TEST(FileIndexTest, IndexAST) { } TEST(FileIndexTest, NoLocal) { - FileIndex M; + FileIndex M(true); update(M, "f1", "namespace ns { void f() { int local = 0; } class X {}; }"); EXPECT_THAT( @@ -207,7 +207,7 @@ TEST(FileIndexTest, NoLocal) { } TEST(FileIndexTest, IndexMultiASTAndDeduplicate) { - FileIndex M; + FileIndex M(true); update(M, "f1", "namespace ns { void f() {} class X {}; }"); update(M, "f2", "namespace ns { void ff() {} class X {}; }"); @@ -219,7 +219,7 @@ TEST(FileIndexTest, IndexMultiASTAndDeduplicate) { } TEST(FileIndexTest, ClassMembers) { - FileIndex M; + FileIndex M(true); update(M, "f1", "class X { static int m1; int m2; static void f(); };"); EXPECT_THAT(runFuzzyFind(M, ""), @@ -228,7 +228,7 @@ TEST(FileIndexTest, ClassMembers) { } TEST(FileIndexTest, IncludeCollected) { - FileIndex M; + FileIndex M(true); update( M, "f", "// IWYU pragma: private, include \nclass string {};"); @@ -240,7 +240,7 @@ TEST(FileIndexTest, IncludeCollected) { } TEST(FileIndexTest, IWYUPragmaExport) { - FileIndex M; + FileIndex M(true); TestTU File; File.Code = R"cpp(#pragma once @@ -286,7 +286,7 @@ template vector make_vector(Arg A) {} )cpp"; - FileIndex M; + FileIndex M(true); update(M, "f", Source); auto Symbols = runFuzzyFind(M, ""); @@ -334,7 +334,7 @@ TEST(FileIndexTest, RebuildWithPreamble) { IgnoreDiagnostics IgnoreDiags; auto CI = buildCompilerInvocation(PI, IgnoreDiags); - FileIndex Index; + FileIndex Index(true); bool IndexUpdated = false; buildPreamble( FooCpp, *CI, PI, @@ -374,7 +374,7 @@ TEST(FileIndexTest, Refs) { RefsRequest Request; Request.IDs = {Foo.ID}; - FileIndex Index; + FileIndex Index(true); // Add test.cc TestTU Test; Test.HeaderCode = HeaderCode; @@ -409,7 +409,7 @@ TEST(FileIndexTest, MacroRefs) { } )cpp"); - FileIndex Index; + FileIndex Index(true); // Add test.cc TestTU Test; Test.HeaderCode = std::string(HeaderCode.code()); @@ -432,7 +432,7 @@ TEST(FileIndexTest, MacroRefs) { } TEST(FileIndexTest, CollectMacros) { - FileIndex M; + FileIndex M(true); update(M, "f", "#define CLANGD 1"); EXPECT_THAT(runFuzzyFind(M, ""), Contains(qName("CLANGD"))); } @@ -443,7 +443,7 @@ TEST(FileIndexTest, Relations) { TU.HeaderFilename = "f.h"; TU.HeaderCode = "class A {}; class B : public A {};"; auto AST = TU.build(); - FileIndex Index; + FileIndex Index(true); Index.updatePreamble(testPath(TU.Filename), /*Version=*/"null", AST.getASTContext(), AST.getPreprocessor(), AST.getPragmaIncludes()); @@ -493,7 +493,7 @@ TEST(FileIndexTest, ReferencesInMainFileWithPreamble) { )cpp"); TU.Code = std::string(Main.code()); auto AST = TU.build(); - FileIndex Index; + FileIndex Index(true); Index.updateMain(testPath(TU.Filename), AST); // Expect to see references in main file, references in headers are excluded @@ -510,7 +510,7 @@ TEST(FileIndexTest, MergeMainFileSymbols) { Cpp.HeaderFilename = "foo.h"; Cpp.HeaderCode = CommonHeader; - FileIndex Index; + FileIndex Index(true); auto HeaderAST = Header.build(); auto CppAST = Cpp.build(); Index.updateMain(testPath("foo.h"), HeaderAST); @@ -524,7 +524,7 @@ TEST(FileIndexTest, MergeMainFileSymbols) { } TEST(FileSymbolsTest, CountReferencesNoRefSlabs) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); FS.update("f1", numSlab(1, 3), nullptr, nullptr, true); FS.update("f2", numSlab(1, 3), nullptr, nullptr, false); EXPECT_THAT( @@ -536,7 +536,7 @@ TEST(FileSymbolsTest, CountReferencesNoRefSlabs) { } TEST(FileSymbolsTest, CountReferencesWithRefSlabs) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); FS.update("f1cpp", numSlab(1, 3), refSlab(SymbolID("1"), "f1.cpp"), nullptr, true); FS.update("f1h", numSlab(1, 3), refSlab(SymbolID("1"), "f1.h"), nullptr, @@ -558,7 +558,7 @@ TEST(FileSymbolsTest, CountReferencesWithRefSlabs) { } TEST(FileIndexTest, StalePreambleSymbolsDeleted) { - FileIndex M; + FileIndex M(true); TestTU File; File.HeaderFilename = "a.h"; @@ -581,7 +581,7 @@ TEST(FileIndexTest, StalePreambleSymbolsDeleted) { // Verifies that concurrent calls to updateMain don't "lose" any updates. TEST(FileIndexTest, Threadsafety) { - FileIndex M; + FileIndex M(true); Notification Go; constexpr int Count = 10; @@ -714,7 +714,7 @@ TEST(FileShardedIndexTest, Sharding) { } TEST(FileIndexTest, Profile) { - FileIndex FI; + FileIndex FI(true); auto FileName = testPath("foo.cpp"); auto AST = TestTU::withHeaderCode("int a;").build(); @@ -738,7 +738,7 @@ TEST(FileIndexTest, Profile) { } TEST(FileSymbolsTest, Profile) { - FileSymbols FS(IndexContents::All); + FileSymbols FS(IndexContents::All, true); FS.update("f1", numSlab(1, 2), nullptr, nullptr, false); FS.update("f2", nullptr, refSlab(SymbolID("1"), "f1"), nullptr, false); FS.update("f3", nullptr, nullptr, @@ -758,7 +758,7 @@ TEST(FileSymbolsTest, Profile) { } TEST(FileIndexTest, MacrosFromMainFile) { - FileIndex Idx; + FileIndex Idx(true); TestTU TU; TU.Code = "#pragma once\n#define FOO"; TU.Filename = "foo.h"; diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 3220a5a6a9825..fc54f89f4941e 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -842,6 +842,8 @@ TEST_F(TargetDeclTest, OverloadExpr) { } TEST_F(TargetDeclTest, DependentExprs) { + Flags.push_back("--std=c++20"); + // Heuristic resolution of method of dependent field Code = R"cpp( struct A { void foo() {} }; @@ -962,6 +964,21 @@ TEST_F(TargetDeclTest, DependentExprs) { }; )cpp"; EXPECT_DECLS("MemberExpr", "void find()"); + + // Base expression is the type of a non-type template parameter + // which is deduced using CTAD. + Code = R"cpp( + template + struct Waldo { + const int found = N; + }; + + template + int test() { + return W.[[found]]; + } + )cpp"; + EXPECT_DECLS("CXXDependentScopeMemberExpr", "const int found = N"); } TEST_F(TargetDeclTest, DependentTypes) { diff --git a/clang-tools-extra/clangd/unittests/IndexTests.cpp b/clang-tools-extra/clangd/unittests/IndexTests.cpp index 658b4e200004e..a66680d39c87d 100644 --- a/clang-tools-extra/clangd/unittests/IndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexTests.cpp @@ -292,7 +292,7 @@ TEST(MergeIndexTest, Lookup) { } TEST(MergeIndexTest, LookupRemovedDefinition) { - FileIndex DynamicIndex, StaticIndex; + FileIndex DynamicIndex(true), StaticIndex(true); MergedIndex Merge(&DynamicIndex, &StaticIndex); const char *HeaderCode = "class Foo;"; @@ -349,7 +349,7 @@ TEST(MergeIndexTest, FuzzyFind) { } TEST(MergeIndexTest, FuzzyFindRemovedSymbol) { - FileIndex DynamicIndex, StaticIndex; + FileIndex DynamicIndex(true), StaticIndex(true); MergedIndex Merge(&DynamicIndex, &StaticIndex); const char *HeaderCode = "class Foo;"; @@ -446,8 +446,8 @@ TEST(MergeTest, PreferSymbolLocationInCodegenFile) { } TEST(MergeIndexTest, Refs) { - FileIndex Dyn; - FileIndex StaticIndex; + FileIndex Dyn(true); + FileIndex StaticIndex(true); MergedIndex Merge(&Dyn, &StaticIndex); const char *HeaderCode = "class Foo;"; diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index 7d9252110b27d..142ed171d1a1c 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -1548,7 +1548,7 @@ TEST(CrossFileRenameTests, DirtyBuffer) { std::string BarPath = testPath("bar.cc"); // Build the index, the index has "Foo" references from foo.cc and "Bar" // references from bar.cc. - FileSymbols FSymbols(IndexContents::All); + FileSymbols FSymbols(IndexContents::All, true); FSymbols.update(FooPath, nullptr, buildRefSlab(FooCode, "Foo", FooPath), nullptr, false); FSymbols.update(BarPath, nullptr, buildRefSlab(BarCode, "Bar", BarPath), @@ -1601,6 +1601,12 @@ TEST(CrossFileRenameTests, DirtyBuffer) { return true; // has more references } + bool containedRefs(const ContainedRefsRequest &Req, + llvm::function_ref + Callback) const override { + return false; + } + bool fuzzyFind( const FuzzyFindRequest &Req, llvm::function_ref Callback) const override { @@ -1652,6 +1658,12 @@ TEST(CrossFileRenameTests, DeduplicateRefsFromIndex) { return false; } + bool containedRefs(const ContainedRefsRequest &Req, + llvm::function_ref + Callback) const override { + return false; + } + bool fuzzyFind(const FuzzyFindRequest &, llvm::function_ref) const override { return false; diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp index 30b9b1902aa9c..1ec51d862d0a6 100644 --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -1092,6 +1092,13 @@ sizeof...($TemplateParameter[[Elements]]); $Field_dependentName[[waldo]]; } }; + )cpp", + // Pointer-to-member with nested-name-specifiers + R"cpp( + struct $Class_def[[Outer]] { + struct $Class_def[[Inner]] {}; + }; + using $Typedef_decl[[Alias]] = void ($Class[[Outer]]::$Class[[Inner]]:: *)(); )cpp"}; for (const auto &TestCase : TestCases) // Mask off scope modifiers to keep the tests manageable. diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp index 1f02c04125b1e..3f8990c86f714 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -174,7 +174,7 @@ RefSlab TestTU::headerRefs() const { std::unique_ptr TestTU::index() const { auto AST = build(); - auto Idx = std::make_unique(); + auto Idx = std::make_unique(/*SupportContainedRefs=*/true); Idx->updatePreamble(testPath(Filename), /*Version=*/"null", AST.getASTContext(), AST.getPreprocessor(), AST.getPragmaIncludes()); diff --git a/clang-tools-extra/clangd/unittests/TestWorkspace.cpp b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp index 2130e7a4c6dd4..e9a50f1e8b63a 100644 --- a/clang-tools-extra/clangd/unittests/TestWorkspace.cpp +++ b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp @@ -17,7 +17,7 @@ namespace clang { namespace clangd { std::unique_ptr TestWorkspace::index() { - auto Index = std::make_unique(); + auto Index = std::make_unique(/*SupportContainedRefs=*/true); for (const auto &Input : Inputs) { if (!Input.second.IsMainFile) continue; diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index d393c72974d44..7d824d659ad2c 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1019,6 +1019,15 @@ TEST(LocateSymbol, All) { void *Value; void *getPointer() const { return Info::get^Pointer(Value); } }; + )cpp", + R"cpp(// Deducing this + struct S { + int bar(this S&); + }; + void foo() { + S [[waldo]]; + int x = wa^ldo.bar(); + } )cpp"}; for (const char *Test : Tests) { Annotations T(Test); @@ -1035,6 +1044,7 @@ TEST(LocateSymbol, All) { TU.Code = std::string(T.code()); TU.ExtraArgs.push_back("-xobjective-c++"); + TU.ExtraArgs.push_back("-std=c++23"); auto AST = TU.build(); auto Results = locateSymbolAt(AST, T.point()); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index f050391110385..b2b66dca6ccf8 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -156,6 +156,10 @@ Changes in existing checks ` check by fixing crashes from invalid code. +- Improved :doc:`bugprone-branch-clone + ` check to improve detection of + branch clones by now detecting duplicate inner and outer if statements. + - Improved :doc:`bugprone-casting-through-void ` check to suggest replacing the offending code with ``reinterpret_cast``, to more clearly express intent. @@ -179,7 +183,9 @@ Changes in existing checks - Improved :doc:`bugprone-return-const-ref-from-parameter ` check to diagnose potential dangling references when returning a ``const &`` parameter - by using the conditional operator ``cond ? var1 : var2``. + by using the conditional operator ``cond ? var1 : var2`` and fixing false + positives for functions which contain lambda and ignore parameters + with ``[[clang::lifetimebound]]`` attribute. - Improved :doc:`bugprone-sizeof-expression ` check to find suspicious @@ -230,6 +236,11 @@ Changes in existing checks ` check by rewording the diagnostic note that suggests adding ``inline``. +- Improved :doc:`misc-redundant-expression + ` check by extending the + checker to detect floating point and integer literals in redundant + expressions. + - Improved :doc:`misc-unconventional-assign-operator ` check to avoid false positive for C++23 deducing this. @@ -237,7 +248,9 @@ Changes in existing checks - Improved :doc:`misc-use-internal-linkage ` check to insert ``static`` keyword before type qualifiers such as ``const`` and ``volatile`` and fix - false positives for function declaration without body. + false positives for function declaration without body and fix false positives + for C++20 export declarations and fix false positives for global scoped + overloaded ``operator new`` and ``operator delete``. - Improved :doc:`modernize-avoid-c-arrays ` check to suggest using diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/branch-clone.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/branch-clone.rst index 0ca34c2bc2320..a91645f32d96f 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/branch-clone.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/branch-clone.rst @@ -32,9 +32,28 @@ If this is the intended behavior, then there is no reason to use a conditional statement; otherwise the issue can be solved by fixing the branch that is handled incorrectly. -The check also detects repeated branches in longer ``if/else if/else`` chains +The check detects repeated branches in longer ``if/else if/else`` chains where it would be even harder to notice the problem. +The check also detects repeated inner and outer ``if`` statements that may +be a result of a copy-paste error. This check cannot currently detect +identical inner and outer ``if`` statements if code is between the ``if`` +conditions. An example is as follows. + +.. code-block:: c++ + + void test_warn_inner_if_1(int x) { + if (x == 1) { // warns, if with identical inner if + if (x == 1) // inner if is here + ; + if (x == 1) { // does not warn, cannot detect + int y = x; + if (x == 1) + ; + } + } + + In ``switch`` statements the check only reports repeated branches when they are consecutive, because it is relatively common that the ``case:`` labels have some natural ordering and rearranging them would decrease the readability of diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/return-const-ref-from-parameter.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/return-const-ref-from-parameter.rst index 2349e51477b7d..ba47399914de3 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/return-const-ref-from-parameter.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/return-const-ref-from-parameter.rst @@ -12,15 +12,6 @@ after the call. When the function returns such a parameter also as constant refe then the returned reference can be used after the object it refers to has been destroyed. -This issue can be resolved by declaring an overload of the problematic function -where the ``const &`` parameter is instead declared as ``&&``. The developer has -to ensure that the implementation of that function does not produce a -use-after-free, the exact error that this check is warning against. -Marking such an ``&&`` overload as ``deleted``, will silence the warning as -well. In the case of different ``const &`` parameters being returned depending -on the control flow of the function, an overload where all problematic -``const &`` parameters have been declared as ``&&`` will resolve the issue. - Example ------- @@ -38,3 +29,23 @@ Example const S& s = fn(S{1}); s.v; // use after free + + +This issue can be resolved by declaring an overload of the problematic function +where the ``const &`` parameter is instead declared as ``&&``. The developer has +to ensure that the implementation of that function does not produce a +use-after-free, the exact error that this check is warning against. +Marking such an ``&&`` overload as ``deleted``, will silence the warning as +well. In the case of different ``const &`` parameters being returned depending +on the control flow of the function, an overload where all problematic +``const &`` parameters have been declared as ``&&`` will resolve the issue. + +This issue can also be resolved by adding ``[[clang::lifetimebound]]``. Clang +enable ``-Wdangling`` warning by default which can detect mis-uses of the +annotated function. See `lifetimebound attribute `_ +for details. + +.. code-block:: c++ + + const int &f(const int &a [[clang::lifetimebound]]) { return a; } // no warning + const int &v = f(1); // warning: temporary bound to local reference 'v' will be destroyed at the end of the full-expression [-Wdangling] diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/redundant-expression.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/redundant-expression.rst index 83c29bd75f5b9..44f0772d0bedf 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc/redundant-expression.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/redundant-expression.rst @@ -23,3 +23,22 @@ Examples: (p->x == p->x) // always true (p->x < p->x) // always false (speed - speed + 1 == 12) // speed - speed is always zero + int b = a | 4 | a // identical expr on both sides + ((x=1) | (x=1)) // expression is identical + +Floats are handled except in the case that NaNs are checked like so: + +.. code-block:: c++ + + int TestFloat(float F) { + if (F == F) // Identical float values used + return 1; + return 0; + } + + int TestFloat(float F) { + // Testing NaN. + if (F != F && F == F) // does not warn + return 1; + return 0; + } diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst index b8bbcc6270610..508b0cac09a91 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst @@ -29,6 +29,11 @@ Example: void fn3(); // without function body in all declaration, maybe external linkage void fn3(); + // export declarations + export void fn4() {} + export namespace t { void fn5() {} } + export int v2; + Options ------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/container-size-empty.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/container-size-empty.rst index b5abd340b9b2b..6a007f69767ab 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/container-size-empty.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/container-size-empty.rst @@ -8,12 +8,10 @@ Checks whether a call to the ``size()``/``length()`` method can be replaced with a call to ``empty()``. The emptiness of a container should be checked using the ``empty()`` method -instead of the ``size()``/``length()`` method. It is not guaranteed that -``size()``/``length()`` is a constant-time function, and it is generally more -efficient and also shows clearer intent to use ``empty()``. Furthermore some -containers may implement the ``empty()`` method but not implement the ``size()`` -or ``length()`` method. Using ``empty()`` whenever possible makes it easier to -switch to another container in the future. +instead of the ``size()``/``length()`` method. It shows clearer intent to use +``empty()``. Furthermore some containers may implement the ``empty()`` method +but not implement the ``size()`` or ``length()`` method. Using ``empty()`` +whenever possible makes it easier to switch to another container in the future. The check issues warning if a container has ``empty()`` and ``size()`` or ``length()`` methods matching following signatures: diff --git a/clang-tools-extra/modularize/ModuleAssistant.cpp b/clang-tools-extra/modularize/ModuleAssistant.cpp index 5c11ffdb8589d..c7259d70bd58f 100644 --- a/clang-tools-extra/modularize/ModuleAssistant.cpp +++ b/clang-tools-extra/modularize/ModuleAssistant.cpp @@ -46,6 +46,8 @@ class Module { public: Module(llvm::StringRef Name, bool Problem); ~Module(); + Module(const Module &other) = delete; + Module &operator=(const Module &other) = delete; bool output(llvm::raw_fd_ostream &OS, int Indent); Module *findSubModule(llvm::StringRef SubName); diff --git a/clang-tools-extra/test/clang-reorder-fields/FieldAnnotationsInMacros.cpp b/clang-tools-extra/test/clang-reorder-fields/FieldAnnotationsInMacros.cpp new file mode 100644 index 0000000000000..aedec9556aa55 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/FieldAnnotationsInMacros.cpp @@ -0,0 +1,9 @@ +// RUN: clang-reorder-fields -record-name Foo -fields-order y,x %s -- | FileCheck %s + +#define GUARDED_BY(x) __attribute__((guarded_by(x))) + +class Foo { + int x GUARDED_BY(x); // CHECK: {{^ int y;}} + int y; // CHECK-NEXT: {{^ int x GUARDED_BY\(x\);}} +}; + diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string index 51f6817416906..7e579e5319752 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string @@ -136,10 +136,6 @@ bool operator==(const std::string&, const std::string&); bool operator==(const std::string&, const char*); bool operator==(const char*, const std::string&); -bool operator!=(const std::string&, const std::string&); -bool operator!=(const std::string&, const char*); -bool operator!=(const char*, const std::string&); - bool operator==(const std::wstring&, const std::wstring&); bool operator==(const std::wstring&, const wchar_t*); bool operator==(const wchar_t*, const std::wstring&); @@ -148,9 +144,15 @@ bool operator==(const std::string_view&, const std::string_view&); bool operator==(const std::string_view&, const char*); bool operator==(const char*, const std::string_view&); +#if __cplusplus < 202002L +bool operator!=(const std::string&, const std::string&); +bool operator!=(const std::string&, const char*); +bool operator!=(const char*, const std::string&); + bool operator!=(const std::string_view&, const std::string_view&); bool operator!=(const std::string_view&, const char*); bool operator!=(const char*, const std::string_view&); +#endif size_t strlen(const char* str); } diff --git a/clang/test/Analysis/identical-expressions.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp similarity index 57% rename from clang/test/Analysis/identical-expressions.cpp rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp index 8bb82372b534a..8eff3ebc948de 100644 --- a/clang/test/Analysis/identical-expressions.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.IdenticalExpr -w -verify %s +// RUN: clang-tidy %s -checks="-*,misc-redundant-expression" -- 2>&1 | FileCheck %s --check-prefix=CHECK-MESSAGES-IDENTEXPR +// RUN: clang-tidy %s -checks="-*,bugprone-branch-clone" -- 2>&1 | FileCheck %s --check-prefix=CHECK-MESSAGES-BUGPRONEBRANCH /* Only one expected warning per function allowed at the very end. */ @@ -65,7 +66,8 @@ int checkNotEqualFloatDeclCompare6(void) { int checkNotEqualCastFloatDeclCompare11(void) { float f = 7.1F; - return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f != (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkNotEqualCastFloatDeclCompare12(void) { float f = 7.1F; @@ -130,7 +132,8 @@ int checkNotEqualNestedBinaryOpFloatCompare3(void) { /* '!=' with int*/ int checkNotEqualIntLiteralCompare1(void) { - return (5 != 5); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (5 != 5); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkNotEqualIntLiteralCompare2(void) { @@ -155,7 +158,8 @@ int checkNotEqualIntDeclCompare4(void) { int checkNotEqualCastIntDeclCompare11(void) { int f = 7; - return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f != (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkNotEqualCastIntDeclCompare12(void) { int f = 7; @@ -166,7 +170,8 @@ int checkNotEqualBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 4; - res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (f + 4 != f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkNotEqualBinaryOpIntCompare2(void) { @@ -181,7 +186,8 @@ int checkNotEqualBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 4; - res = ((int)f + 4 != (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = ((int)f + 4 != (int)f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkNotEqualBinaryOpIntCompare4(void) { @@ -196,7 +202,8 @@ int checkNotEqualBinaryOpIntCompare5(void) { int res; int t= 1; int u= 2; - res = (u + t != u + t); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (u + t != u + t); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -205,7 +212,8 @@ int checkNotEqualNestedBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (3 - u)*t) != ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (3 - u)*t) != ((int)f + (3 - u)*t)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -223,7 +231,8 @@ int checkNotEqualNestedBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*(t + 1 != t + 1))); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*(t + 1 != t + 1))); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:59: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -252,7 +261,8 @@ int checkNotEqualIntPointerDeclCompare1(void) { int checkNotEqualCastIntPointerDeclCompare11(void) { int k = 7; int* f = &k; - return ((int*)f != (int*)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int*)f != (int*)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkNotEqualCastIntPointerDeclCompare12(void) { int k = 7; @@ -263,7 +273,8 @@ int checkNotEqualBinaryOpIntPointerCompare1(void) { int k = 7; int res; int* f= &k; - res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (f + 4 != f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkNotEqualBinaryOpIntPointerCompare2(void) { @@ -278,7 +289,8 @@ int checkNotEqualBinaryOpIntPointerCompare3(void) { int k = 7; int res; int* f= &k; - res = ((int*)f + 4 != (int*)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = ((int*)f + 4 != (int*)f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:22: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkNotEqualBinaryOpIntPointerCompare4(void) { @@ -295,7 +307,8 @@ int checkNotEqualNestedBinaryOpIntPointerCompare1(void) { int t= 1; int* u= &k+2; int* f= &k+3; - res = ((f + (3)*t) != (f + (3)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = ((f + (3)*t) != (f + (3)*t)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:22: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -358,7 +371,8 @@ int checkEqualIntPointerDeclCompare(void) { int checkEqualIntPointerDeclCompare0(void) { int k = 3; int* f = &k; - return (f+1 == f+1); // expected-warning {{comparison of identical expressions always evaluates to true}} + return (f+1 == f+1); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:15: warning: both sides of operator are equivalent [misc-redundant-expression] } /* EQ with float*/ @@ -410,7 +424,8 @@ int checkEqualFloatDeclCompare6(void) { int checkEqualCastFloatDeclCompare11(void) { float f = 7.1F; - return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}} + return ((int)f == (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkEqualCastFloatDeclCompare12(void) { float f = 7.1F; @@ -474,7 +489,8 @@ int checkEqualNestedBinaryOpFloatCompare3(void) { /* Equal with int*/ int checkEqualIntLiteralCompare1(void) { - return (5 == 5); // expected-warning {{comparison of identical expressions always evaluates to true}} + return (5 == 5); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkEqualIntLiteralCompare2(void) { @@ -489,7 +505,8 @@ int checkEqualIntDeclCompare1(void) { int checkEqualCastIntDeclCompare11(void) { int f = 7; - return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}} + return ((int)f == (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkEqualCastIntDeclCompare12(void) { int f = 7; @@ -511,7 +528,8 @@ int checkEqualBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 4; - res = (f + 4 == f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}} + res = (f + 4 == f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkEqualBinaryOpIntCompare2(void) { @@ -526,7 +544,8 @@ int checkEqualBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 4; - res = ((int)f + 4 == (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}} + res = ((int)f + 4 == (int)f + 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -542,7 +561,8 @@ int checkEqualBinaryOpIntCompare5(void) { int res; int t= 1; int u= 2; - res = (u + t == u + t); // expected-warning {{comparison of identical expressions always evaluates to true}} + res = (u + t == u + t); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -551,7 +571,8 @@ int checkEqualNestedBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (3 - u)*t) == ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to true}} + res = (((int)f + (3 - u)*t) == ((int)f + (3 - u)*t)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -569,7 +590,8 @@ int checkEqualNestedBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*(t + 1 == t + 1))); // expected-warning {{comparison of identical expressions always evaluates to true}} + res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*(t + 1 == t + 1))); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:59: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -615,7 +637,8 @@ int checkEqualSameFunctionDifferentParam() { /* LT with float */ int checkLessThanFloatLiteralCompare1(void) { - return (5.14F < 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (5.14F < 5.14F); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkLessThanFloatLiteralCompare2(void) { @@ -630,7 +653,8 @@ int checkLessThanFloatDeclCompare1(void) { int checkLessThanFloatDeclCompare12(void) { float f = 7.1F; - return (f < f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (f < f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkLessThanFloatDeclCompare3(void) { @@ -658,7 +682,8 @@ int checkLessThanFloatDeclCompare6(void) { int checkLessThanCastFloatDeclCompare11(void) { float f = 7.1F; - return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f < (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkLessThanCastFloatDeclCompare12(void) { float f = 7.1F; @@ -721,7 +746,8 @@ int checkLessThanNestedBinaryOpFloatCompare3(void) { int checkLessThanIntLiteralCompare1(void) { - return (5 < 5); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (5 < 5); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkLessThanIntLiteralCompare2(void) { @@ -758,7 +784,8 @@ int checkLessThanIntDeclCompare6(void) { int checkLessThanCastIntDeclCompare11(void) { int f = 7; - return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f < (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkLessThanCastIntDeclCompare12(void) { int f = 7; @@ -767,7 +794,8 @@ int checkLessThanCastIntDeclCompare12(void) { int checkLessThanBinaryOpIntCompare1(void) { int res; int f= 3; - res = (f + 3 < f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (f + 3 < f + 3); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkLessThanBinaryOpIntCompare2(void) { @@ -778,7 +806,8 @@ int checkLessThanBinaryOpIntCompare2(void) { int checkLessThanBinaryOpIntCompare3(void) { int res; int f= 3; - res = ((int)f + 3 < (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = ((int)f + 3 < (int)f + 3); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkLessThanBinaryOpIntCompare4(void) { @@ -793,7 +822,8 @@ int checkLessThanNestedBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (3 - u)*t) < ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (3 - u)*t) < ((int)f + (3 - u)*t)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -811,7 +841,8 @@ int checkLessThanNestedBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*(t + u < t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*(t + u < t + u))); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:58: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -825,7 +856,8 @@ int checkLessThanNestedBinaryOpIntCompare3(void) { /* GT with float */ int checkGreaterThanFloatLiteralCompare1(void) { - return (5.14F > 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (5.14F > 5.14F); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkGreaterThanFloatLiteralCompare2(void) { @@ -841,7 +873,8 @@ int checkGreaterThanFloatDeclCompare1(void) { int checkGreaterThanFloatDeclCompare12(void) { float f = 7.1F; - return (f > f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (f > f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } @@ -869,7 +902,8 @@ int checkGreaterThanFloatDeclCompare6(void) { int checkGreaterThanCastFloatDeclCompare11(void) { float f = 7.1F; - return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f > (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkGreaterThanCastFloatDeclCompare12(void) { float f = 7.1F; @@ -932,7 +966,8 @@ int checkGreaterThanNestedBinaryOpFloatCompare3(void) { int checkGreaterThanIntLiteralCompare1(void) { - return (5 > 5); // expected-warning {{comparison of identical expressions always evaluates to false}} + return (5 > 5); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkGreaterThanIntLiteralCompare2(void) { @@ -958,7 +993,8 @@ int checkGreaterThanIntDeclCompare4(void) { int checkGreaterThanCastIntDeclCompare11(void) { int f = 7; - return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}} + return ((int)f > (int)f); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } int checkGreaterThanCastIntDeclCompare12(void) { int f = 7; @@ -967,7 +1003,8 @@ int checkGreaterThanCastIntDeclCompare12(void) { int checkGreaterThanBinaryOpIntCompare1(void) { int res; int f= 3; - res = (f + 3 > f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (f + 3 > f + 3); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkGreaterThanBinaryOpIntCompare2(void) { @@ -978,7 +1015,8 @@ int checkGreaterThanBinaryOpIntCompare2(void) { int checkGreaterThanBinaryOpIntCompare3(void) { int res; int f= 3; - res = ((int)f + 3 > (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = ((int)f + 3 > (int)f + 3); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } int checkGreaterThanBinaryOpIntCompare4(void) { @@ -993,7 +1031,8 @@ int checkGreaterThanNestedBinaryOpIntCompare1(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (3 - u)*t) > ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (3 - u)*t) > ((int)f + (3 - u)*t)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -1011,7 +1050,8 @@ int checkGreaterThanNestedBinaryOpIntCompare3(void) { int t= 1; int u= 2; int f= 3; - res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*(t + u > t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}} + res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*(t + u > t + u))); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:58: warning: both sides of operator are equivalent [misc-redundant-expression] return (0); } @@ -1024,45 +1064,61 @@ int checkGreaterThanNestedBinaryOpIntCompare3(void) { unsigned test_unsigned(unsigned a) { unsigned b = 1; - a = a > 5 ? b : b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? b : b; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] return a; } void test_signed() { int a = 0; - a = a > 5 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a : a; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_bool(bool a) { - a = a > 0 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 0 ? a : a; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_float() { float a = 0; float b = 0; - a = a > 5 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a : a; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } const char *test_string() { float a = 0; - return a > 5 ? "abc" : "abc"; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + return a > 5 ? "abc" : "abc"; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:16: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_unsigned_expr() { unsigned a = 0; unsigned b = 0; - a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+b : a+b; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_signed_expr() { int a = 0; int b = 1; - a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+b : a+b; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_bool_expr(bool a) { bool b = 0; - a = a > 0 ? a&&b : a&&b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 0 ? a&&b : a&&b; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:20: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_unsigned_expr_negative() { @@ -1085,13 +1141,17 @@ void test_bool_expr_negative(bool a) { void test_float_expr_positive() { float a = 0; float b = 0; - a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+b : a+b; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_expr_positive_func() { unsigned a = 0; unsigned b = 1; - a = a > 5 ? a+func() : a+func(); // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+func() : a+func(); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_expr_negative_func() { @@ -1103,7 +1163,9 @@ void test_expr_negative_func() { void test_expr_positive_funcParam() { unsigned a = 0; unsigned b = 1; - a = a > 5 ? a+funcParam(b) : a+funcParam(b); // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+funcParam(b) : a+funcParam(b); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:30: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_expr_negative_funcParam() { @@ -1115,7 +1177,8 @@ void test_expr_negative_funcParam() { void test_expr_positive_inc() { unsigned a = 0; unsigned b = 1; - a = a > 5 ? a++ : a++; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a++ : a++; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_expr_negative_inc() { @@ -1127,7 +1190,8 @@ void test_expr_negative_inc() { void test_expr_positive_assign() { unsigned a = 0; unsigned b = 1; - a = a > 5 ? a=1 : a=1; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a=1 : a=1; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_expr_negative_assign() { @@ -1140,7 +1204,9 @@ void test_signed_nested_expr() { int a = 0; int b = 1; int c = 3; - a = a > 5 ? a+b+(c+a)*(a + b*(c+a)) : a+b+(c+a)*(a + b*(c+a)); // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? a+b+(c+a)*(a + b*(c+a)) : a+b+(c+a)*(a + b*(c+a)); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:39: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_signed_nested_expr_negative() { @@ -1161,23 +1227,29 @@ void test_signed_nested_cond_expr() { int a = 0; int b = 1; int c = 3; - a = a > 5 ? (b > 5 ? 1 : 4) : (b > 5 ? 4 : 4); // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + a = a > 5 ? (b > 5 ? 1 : 4) : (b > 5 ? 4 : 4); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:44: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:40: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_identical_branches1(bool b) { int i = 0; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] ++i; } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here ++i; } } void test_identical_branches2(bool b) { int i = 0; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] ++i; } else +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here ++i; } @@ -1192,33 +1264,41 @@ void test_identical_branches3(bool b) { void test_identical_branches4(bool b) { int i = 0; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here } } void test_identical_branches_break(bool b) { while (true) { - if (b) // expected-warning {{true and false branches are identical}} + if (b) +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] break; else +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here break; } } void test_identical_branches_continue(bool b) { while (true) { - if (b) // expected-warning {{true and false branches are identical}} + if (b) +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] continue; else +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here continue; } } void test_identical_branches_func(bool b) { - if (b) // expected-warning {{true and false branches are identical}} + if (b) +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] func(); else +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: note: else branch starts here func(); } @@ -1239,27 +1319,33 @@ void test_identical_branches_cast1(bool b) { void test_identical_branches_cast2(bool b) { long v = -7; - if (b) // expected-warning {{true and false branches are identical}} + if (b) +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] v = (signed int) v; else +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: note: else branch starts here v = (signed int) v; } int test_identical_branches_return_int(bool b) { int i = 0; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] i++; return i; } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here i++; return i; } } int test_identical_branches_return_func(bool b) { - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] return func(); } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here return func(); } } @@ -1267,10 +1353,12 @@ int test_identical_branches_return_func(bool b) { void test_identical_branches_for(bool b) { int i; int j; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] for (i = 0, j = 0; i < 10; i++) j += 4; } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here for (i = 0, j = 0; i < 10; i++) j += 4; } @@ -1278,10 +1366,12 @@ void test_identical_branches_for(bool b) { void test_identical_branches_while(bool b) { int i = 10; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] while (func()) i--; } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here while (func()) i--; } @@ -1300,11 +1390,13 @@ void test_identical_branches_while_2(bool b) { void test_identical_branches_do_while(bool b) { int i = 10; - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] do { i--; } while (func()); } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here do { i--; } while (func()); @@ -1312,27 +1404,32 @@ void test_identical_branches_do_while(bool b) { } void test_identical_branches_if(bool b, int i) { - if (b) { // expected-warning {{true and false branches are identical}} + if (b) { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] if (i < 5) i += 10; } else { +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here if (i < 5) i += 10; } } void test_identical_bitwise1() { - int a = 5 | 5; // expected-warning {{identical expressions on both sides of bitwise operator}} + int a = 5 | 5; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } void test_identical_bitwise2() { int a = 5; - int b = a | a; // expected-warning {{identical expressions on both sides of bitwise operator}} + int b = a | a; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression] } void test_identical_bitwise3() { int a = 5; - int b = (a | a); // expected-warning {{identical expressions on both sides of bitwise operator}} + int b = (a | a); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:14: warning: both sides of operator are equivalent [misc-redundant-expression] } void test_identical_bitwise4() { @@ -1348,21 +1445,25 @@ void test_identical_bitwise5() { void test_identical_bitwise6() { int a = 5; - int b = a | 4 | a; // expected-warning {{identical expressions on both sides of bitwise operator}} + int b = a | 4 | a; +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: operator has equivalent nested operands [misc-redundant-expression] } void test_identical_bitwise7() { int a = 5; - int b = func() | func(); // no-warning + int b = func() | func(); +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression] } void test_identical_logical1(int a) { - if (a == 4 && a == 4) // expected-warning {{identical expressions on both sides of logical operator}} + if (a == 4 && a == 4) +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:14: warning: both sides of operator are equivalent [misc-redundant-expression] ; } void test_identical_logical2(int a) { - if (a == 4 || a == 5 || a == 4) // expected-warning {{identical expressions on both sides of logical operator}} + if (a == 4 || a == 5 || a == 4) +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: operator has equivalent nested operands [misc-redundant-expression] ; } @@ -1384,7 +1485,8 @@ void test_identical_logical5(int x, int y) { } void test_identical_logical6(int x, int y) { - if (x == 4 && y == 5 || x == 4 && y == 5) // expected-warning {{identical expressions on both sides of logical operator}} + if (x == 4 && y == 5 || x == 4 && y == 5) +// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: both sides of operator are equivalent [misc-redundant-expression] ; } @@ -1410,51 +1512,73 @@ void test_identical_logical9(int x, int y) { void test_warn_chained_if_stmts_1(int x) { if (x == 1) ; - else if (x == 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original + else if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here } void test_warn_chained_if_stmts_2(int x) { if (x == 1) ; - else if (x == 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original + else if (x == 1) ; - else if (x == 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here + else if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here } void test_warn_chained_if_stmts_3(int x) { if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (x == 2) ; - else if (x == 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here + else if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here } void test_warn_chained_if_stmts_4(int x) { if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (func()) ; - else if (x == 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here + else if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here } void test_warn_chained_if_stmts_5(int x) { if (x & 1) ; - else if (x & 1) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original + else if (x & 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here } void test_warn_chained_if_stmts_6(int x) { if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (x == 2) ; - else if (x == 2) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here + else if (x == 2) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here else if (x == 3) ; } @@ -1462,58 +1586,83 @@ void test_warn_chained_if_stmts_6(int x) { void test_warn_chained_if_stmts_7(int x) { if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (x == 2) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here else if (x == 3) ; - else if (x == 2) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here + else if (x == 2) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 3 starts here else if (x == 5) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here } void test_warn_chained_if_stmts_8(int x) { if (x == 1) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (x == 2) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here else if (x == 3) ; - else if (x == 2) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here + else if (x == 2) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 3 starts here else if (x == 5) ; - else if (x == 3) // expected-warning {{expression is identical to previous condition}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here + else if (x == 3) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 5 starts here else if (x == 7) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 6 starts here } void test_nowarn_chained_if_stmts_1(int x) { if (func()) ; - else if (func()) // no-warning +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original + else if (func()) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here } void test_nowarn_chained_if_stmts_2(int x) { if (func()) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original else if (x == 1) ; - else if (func()) // no-warning +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here + else if (func()) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here } void test_nowarn_chained_if_stmts_3(int x) { if (x++) ; - else if (x++) // no-warning +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original + else if (x++) ; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here } void test_warn_wchar() { - const wchar_t * a = 0 ? L"Warning" : L"Warning"; // expected-warning {{identical expressions on both sides of ':' in conditional expression}} + const wchar_t * a = 0 ? L"Warning" : L"Warning"; +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:25: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] } void test_nowarn_wchar() { const wchar_t * a = 0 ? L"No" : L"Warning"; @@ -1525,7 +1674,7 @@ void test_nowarn_long() { if (0) { b -= a; c = 0; - } else { // no-warning + } else { b -= a; c = 0LL; } @@ -1535,7 +1684,9 @@ void test_nowarn_long() { void test_warn_inner_if_1(int x) { if (x == 1) { - if (x == 1) // expected-warning {{conditions of the inner and outer statements are identical}} +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical inner if statement [bugprone-branch-clone] + if (x == 1) +// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: inner if starts here ; } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp index d83d997a455d5..a3297ca0f8084 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp @@ -76,6 +76,9 @@ struct C { // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter }; +const auto Lf1 = [](const T& t) -> const T& { return t; }; +// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter + } // namespace invalid namespace false_negative_because_dependent_and_not_instantiated { @@ -151,6 +154,14 @@ void instantiate(const int ¶m, const float ¶mf, int &mut_param, float &m itf6(mut_paramf); } +template +void f(const T& t) { + const auto get = [&t] -> const T& { return t; }; + return T{}; +} + +const auto Lf1 = [](T& t) -> const T& { return t; }; + } // namespace valid namespace overload { @@ -186,3 +197,32 @@ int const &overload_params_difference3(int p1, int const &a, int p2) { return a; int const &overload_params_difference3(int p1, long &&a, int p2); } // namespace overload + +namespace gh117696 { +namespace use_lifetime_bound_attr { +int const &f(int const &a [[clang::lifetimebound]]) { return a; } +} // namespace use_lifetime_bound_attr +} // namespace gh117696 + + +namespace lambda { +using T = const int &; +using K = const float &; +T inner_valid_lambda(T a) { + [&]() -> T { return a; }; + return a; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter +} +T inner_invalid_lambda(T a) { + [&](T a) -> T { return a; }; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: returning a constant reference parameter + return a; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter +} +T inner_invalid_lambda2(T a) { + [&](K a) -> K { return a; }; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: returning a constant reference parameter + return a; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: returning a constant reference parameter +} +} // namespace lambda diff --git a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp index ed9079092f6ac..50b6d4c5676c3 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/fuchsia/default-arguments-calls.cpp @@ -26,7 +26,7 @@ void S::x(int i = 12) {} int main() { S s; s.x(); - // CHECK-NOTES: [[@LINE-1]]:3: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls] + // CHECK-NOTES: [[@LINE-1]]:5: warning: calling a function that uses a default argument is disallowed [fuchsia-default-arguments-calls] // CHECK-NOTES: [[@LINE-6]]:11: note: default parameter was declared here // CHECK-NEXT: void S::x(int i = 12) {} x(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp index 1b271630e0d19..7396d2dce76c4 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -fno-delayed-template-parsing -Wno-array-compare-cxx26 typedef __INT64_TYPE__ I64; diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp index bf0d2c2513e56..68951fcf0aaac 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp @@ -85,3 +85,13 @@ void func_with_body() {} void func_without_body(); void func_without_body(); } + +// gh117489 start +namespace std { +using size_t = decltype(sizeof(int)); +} +void * operator new(std::size_t) { return nullptr; } +void * operator new[](std::size_t) { return nullptr; } +void operator delete(void*) noexcept {} +void operator delete[](void*) noexcept {} +// gh117489 end diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-module.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-module.cpp new file mode 100644 index 0000000000000..9b0d8cde429b6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-module.cpp @@ -0,0 +1,20 @@ +// RUN: %check_clang_tidy -std=c++20 %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage + +module; + +export module test; + +export void single_export_fn() {} +export int single_export_var; + +export { + void group_export_fn1() {} + void group_export_fn2() {} + int group_export_var1; + int group_export_var2; +} + +export namespace aa { +void namespace_export_fn() {} +int namespace_export_var; +} // namespace aa diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp index 18a65f7f1cf26..8699ca03ba331 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-starts-ends-with.cpp @@ -320,3 +320,13 @@ void test_substr() { str.substr(0, strlen("hello123")) == "hello"; } + +void test_operator_rewriting(std::string str, std::string prefix) { + str.substr(0, prefix.size()) == prefix; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of substr + // CHECK-FIXES: str.starts_with(prefix); + + str.substr(0, prefix.size()) != prefix; + // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of substr + // CHECK-FIXES: !str.starts_with(prefix); +} diff --git a/clang/Maintainers.rst b/clang/Maintainers.rst index 7396211715a80..13242fa42684e 100644 --- a/clang/Maintainers.rst +++ b/clang/Maintainers.rst @@ -320,8 +320,8 @@ OpenMP conformance OpenCL conformance ~~~~~~~~~~~~~~~~~~ -| Anastasia Stulova -| anastasia\@compiler-experts.com (email), Anastasia (Phabricator), AnastasiaStulova (GitHub) +| Sven van Haastregt +| sven.vanhaastregt@arm.com (email), svenvh (GitHub) OpenACC @@ -365,6 +365,7 @@ Emeritus Lead Maintainers Inactive component maintainers ------------------------------ +| Anastasia Stulova (stulovaa\@gmail.com) -- OpenCL, C++ for OpenCL | Chandler Carruth (chandlerc\@gmail.com, chandlerc\@google.com) -- CMake, library layering | Devin Coughlin (dcoughlin\@apple.com) -- Clang static analyzer | Manuel Klimek (klimek\@google.com (email), klimek (Phabricator), r4nt (GitHub)) -- Tooling, AST matchers diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index 853217c6db61a..c47c4ac3bb73e 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -96,7 +96,11 @@ endif() if (NOT DEFINED TOOLCHAIN_SHARED_LIBS) set(TOOLCHAIN_SHARED_LIBS OFF) endif() - +# Enable usage of the static libunwind and libc++abi libraries. +if (NOT DEFINED TOOLCHAIN_USE_STATIC_LIBS) + set(TOOLCHAIN_USE_STATIC_LIBS ON) +endif() + if (NOT DEFINED LLVM_TARGETS_TO_BUILD) if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(armv|arm32)+") set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "") @@ -206,7 +210,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_USE_COMPILER_RT set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "") -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_STATIC_UNWINDER ${TOOLCHAIN_USE_STATIC_LIBS} CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "") @@ -217,7 +221,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!! set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "") # Merge libc++ and libc++abi libraries into the single libc++ library file. -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ${TOOLCHAIN_USE_STATIC_LIBS} CACHE BOOL "") # Forcely disable the libc++ benchmarks on Windows build hosts # (current benchmark test configuration does not support the cross builds there). if (WIN32) diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 304e7833699a7..8e161f868d4af 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -6,7 +6,7 @@ set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64;RISCV CACHE STRING "") set(PACKAGE_VENDOR Fuchsia CACHE STRING "") -set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;libc;lld;llvm;polly") +set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;lld;llvm;polly") set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "") set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "") @@ -25,8 +25,6 @@ set(LLVM_ENABLE_ZLIB ON CACHE BOOL "") set(LLVM_FORCE_BUILD_RUNTIME ON CACHE BOOL "") set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "") set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "") -set(LLVM_LIBC_FULL_BUILD ON CACHE BOOL "") -set(LIBC_HDRGEN_ONLY ON CACHE BOOL "") set(LLVM_STATIC_LINK_CXX_STDLIB ON CACHE BOOL "") set(LLVM_USE_RELATIVE_PATHS_IN_FILES ON CACHE BOOL "") set(LLDB_ENABLE_CURSES OFF CACHE BOOL "") @@ -302,19 +300,22 @@ if(FUCHSIA_SDK) set(LLVM_RUNTIME_MULTILIB_hwasan+noexcept_TARGETS "aarch64-unknown-fuchsia;riscv64-unknown-fuchsia" CACHE STRING "") endif() -foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m.main-none-eabi) +foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m.main-none-eabi;aarch64-none-elf) list(APPEND BUILTIN_TARGETS "${target}") set(BUILTINS_${target}_CMAKE_SYSTEM_NAME Generic CACHE STRING "") set(BUILTINS_${target}_CMAKE_SYSTEM_PROCESSOR arm CACHE STRING "") set(BUILTINS_${target}_CMAKE_SYSROOT "" CACHE STRING "") set(BUILTINS_${target}_CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "") foreach(lang C;CXX;ASM) - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target}") + if(NOT ${target} STREQUAL "aarch64-none-elf") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mthumb") + endif() if(${target} STREQUAL "armv8m.main-none-eabi") - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33") endif() if(${target} STREQUAL "armv8.1m.main-none-eabi") - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55" CACHE STRING "") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55") endif() set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "${BUILTINS_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() @@ -332,12 +333,15 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi;armv8.1m. foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1") + if(NOT ${target} STREQUAL "aarch64-none-elf") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mthumb") + endif() if(${target} STREQUAL "armv8m.main-none-eabi") - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33") endif() if(${target} STREQUAL "armv8.1m.main-none-eabi") - set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8.1-m.main+mve.fp+fp.dp -mcpu=cortex-m55") endif() set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "${RUNTIMES_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake index 2d2dcb9ae6798..07637cd0ed08f 100644 --- a/clang/cmake/caches/Fuchsia.cmake +++ b/clang/cmake/caches/Fuchsia.cmake @@ -6,7 +6,7 @@ set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64;RISCV CACHE STRING "") set(PACKAGE_VENDOR Fuchsia CACHE STRING "") -set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;libc;lld;llvm;polly") +set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;lld;llvm;polly") set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "") set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "") @@ -17,7 +17,6 @@ set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "") set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "") set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "") set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "") -set(LIBC_HDRGEN_ONLY ON CACHE BOOL "") set(LLVM_USE_RELATIVE_PATHS_IN_FILES ON CACHE BOOL "") set(LLDB_ENABLE_CURSES OFF CACHE BOOL "") set(LLDB_ENABLE_LIBEDIT OFF CACHE BOOL "") diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index e17d741b0a00e..c8f1d7f5a7758 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -49,7 +49,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. supported: CSharp: .cs Java: .java - JavaScript: .mjs .js .ts + JavaScript: .js .mjs .cjs .ts Json: .json Objective-C: .m .mm Proto: .proto .protodevel diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index dc34094b5053a..4be448171699c 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3759,9 +3759,9 @@ the configuration (without a prefix: ``Auto``). lists. Important differences: - - No spaces inside the braced list. - - No line break before the closing brace. - - Indentation with the continuation indent, not with the block indent. + * No spaces inside the braced list. + * No line break before the closing brace. + * Indentation with the continuation indent, not with the block indent. Fundamentally, C++11 braced lists are formatted exactly like function calls would be formatted in their place. If the braced list follows a name @@ -4104,10 +4104,10 @@ the configuration (without a prefix: ``Auto``). When guessing whether a #include is the "main" include (to assign category 0, see above), use this regex of allowed suffixes to the header stem. A partial match is done, so that: - - "" means "arbitrary suffix" - - "$" means "no suffix" + * ``""`` means "arbitrary suffix" + * ``"$"`` means "no suffix" - For example, if configured to "(_test)?$", then a header a.h would be seen + For example, if configured to ``"(_test)?$"``, then a header a.h would be seen as the "main" include in both a.cc and a_test.cc. .. _IncludeIsMainSourceRegex: @@ -5313,21 +5313,21 @@ the configuration (without a prefix: ``Auto``). **QualifierOrder** (``List of Strings``) :versionbadge:`clang-format 14` :ref:`¶ ` The order in which the qualifiers appear. - Order is an array that can contain any of the following: + The order is an array that can contain any of the following: - * const - * inline - * static - * friend - * constexpr - * volatile - * restrict - * type + * ``const`` + * ``inline`` + * ``static`` + * ``friend`` + * ``constexpr`` + * ``volatile`` + * ``restrict`` + * ``type`` .. note:: - It **must** contain ``type``. + It must contain ``type``. Items to the left of ``type`` will be placed to the left of the type and aligned in the order supplied. Items to the right of ``type`` will be @@ -6645,12 +6645,11 @@ the configuration (without a prefix: ``Auto``). .. _StatementMacros: **StatementMacros** (``List of Strings``) :versionbadge:`clang-format 8` :ref:`¶ ` - A vector of macros that should be interpreted as complete - statements. + A vector of macros that should be interpreted as complete statements. - Typical macros are expressions, and require a semi-colon to be - added; sometimes this is not the case, and this allows to make - clang-format aware of such cases. + Typical macros are expressions and require a semicolon to be added. + Sometimes this is not the case, and this allows to make clang-format aware + of such cases. For example: Q_UNUSED diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index c82e3b017b9d1..475a6372ca696 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -648,7 +648,8 @@ elementwise to the input. Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``, -can be called in a ``constexpr`` context. +``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``, +``__builtin_elementwise_sub_sat`` can be called in a ``constexpr`` context. ============================================== ====================================================================== ========================================= Name Operation Supported element types @@ -1989,7 +1990,7 @@ Enumerations with a fixed underlying type ----------------------------------------- Clang provides support for C++11 enumerations with a fixed underlying type -within Objective-C. For example, one can write an enumeration type as: +within Objective-C and C `prior to C23 `_. For example, one can write an enumeration type as: .. code-block:: c++ @@ -2001,6 +2002,14 @@ value, is ``unsigned char``. Use ``__has_feature(objc_fixed_enum)`` to determine whether support for fixed underlying types is available in Objective-C. +Use ``__has_extension(c_fixed_enum)`` to determine whether support for fixed +underlying types is available in C prior to C23. This will also report ``true`` in C23 +and later modes as the functionality is available even if it's not an extension in +those modes. + +Use ``__has_feature(c_fixed_enum)`` to determine whether support for fixed +underlying types is available in C23 and later. + Interoperability with C++11 lambdas ----------------------------------- diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index c6307954d7f1b..f18e9cf134169 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -804,6 +804,17 @@

Node Matchers

+Matcher<Decl>exportDeclMatcher<ExportDecl>... +
Matches any export declaration.
+
+Example matches following declarations.
+  export void foo();
+  export { void foo(); }
+  export namespace { void foo(); }
+  export int v;
+
+ + Matcher<Decl>fieldDeclMatcher<FieldDecl>...
Matches field declarations.
 
diff --git a/clang/docs/RealtimeSanitizer.rst b/clang/docs/RealtimeSanitizer.rst
index 233a91f668416..f5d29af2bef3c 100644
--- a/clang/docs/RealtimeSanitizer.rst
+++ b/clang/docs/RealtimeSanitizer.rst
@@ -187,16 +187,19 @@ A **partial** list of flags RealtimeSanitizer respects:
    * - ``abort_on_error``
      - OS dependent
      - boolean
-     - If true, the tool calls abort() instead of _exit() after printing the error report. On some OSes (OSX, for exmple) this is beneficial because a better stack trace is emitted on crash.
+     - If true, the tool calls ``abort()`` instead of ``_exit()`` after printing the error report. On some OSes (MacOS, for exmple) this is beneficial because a better stack trace is emitted on crash.
    * - ``symbolize``
      - ``true``
      - boolean
      - If set, use the symbolizer to turn virtual addresses to file/line locations. If false, can greatly speed up the error reporting.
    * - ``suppressions``
-     - ""
+     - ``""``
      - path
-     - If set to a valid suppressions file, will suppress issue reporting. See details in "Disabling", below.
-
+     - If set to a valid suppressions file, will suppress issue reporting. See details in `Disabling and Suppressing`_.
+   * - ``verify_interceptors``
+     - ``true``
+     - boolean
+     - If true, verifies interceptors are working at initialization. The program will abort with error ``==ERROR: Interceptors are not working. This may be because RealtimeSanitizer is loaded too late (e.g. via dlopen)`` if an issue is detected.
 
 Some issues with flags can be debugged using the ``verbosity=$NUM`` flag:
 
@@ -244,6 +247,7 @@ To register a callback which will be invoked before a RTSan kills the process:
     ...
   }
 
+.. _disabling-and-suppressing:
 
 Disabling and suppressing
 -------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6c40e48e2f49b..a541d399d1e74 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -52,6 +52,12 @@ code bases.
   `migrate to Vulkan `_
   or other options.
 
+- Clang now emits distinct type-based alias analysis tags for incompatible
+  pointers by default, enabling more powerful alias analysis when accessing
+  pointer types. This change may silently change code behavior for code
+  containing strict-aliasing violations. The new default behavior can be
+  disabled using ``-fno-pointer-tbaa``.
+
 C/C++ Language Potentially Breaking Changes
 -------------------------------------------
 
@@ -158,6 +164,35 @@ C++ Specific Potentially Breaking Changes
 
   Previously, this code was erroneously accepted.
 
+- Clang will now consider the implicitly deleted destructor of a union or
+  a non-union class without virtual base class to be ``constexpr`` in C++20
+  mode (Clang 19 only did so in C++23 mode but the standard specification for
+  this changed in C++20). (#GH85550)
+
+  .. code-block:: c++
+
+    struct NonLiteral {
+      NonLiteral() {}
+      ~NonLiteral() {}
+    };
+
+    template 
+    struct Opt {
+      union {
+        char c;
+        T data;
+      };
+      bool engaged = false;
+
+      constexpr Opt() {}
+      constexpr ~Opt() {
+        if (engaged)
+          data.~T();
+      }
+    };
+
+    // Previously only accepted in C++23 and later, now also accepted in C++20.
+    consteval void foo() { Opt{}; }
 
 ABI Changes in This Version
 ---------------------------
@@ -227,6 +262,8 @@ C++2c Feature Support
 - Added the ``__builtin_is_within_lifetime`` builtin, which supports
   `P2641R4 Checking if a union alternative is active `_
 
+- Implemented `P3176R1 The Oxford variadic comma `_
+
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 - Removed the restriction to literal types in constexpr functions in C++23 mode.
@@ -279,6 +316,9 @@ Resolutions to C++ Defect Reports
   by default.
   (`CWG2521: User-defined literals and reserved identifiers `_).
 
+- Fix name lookup for a dependent base class that is the current instantiation.
+  (`CWG591: When a dependent base class is the current instantiation `_).
+
 C Language Changes
 ------------------
 
@@ -347,7 +387,7 @@ Non-comprehensive list of changes in this release
 
 - The new builtin ``__builtin_counted_by_ref`` was added. In contexts where the
   programmer needs access to the ``counted_by`` attribute's field, but it's not
-  available --- e.g. in macros. For instace, it can be used to automatically
+  available --- e.g. in macros. For instance, it can be used to automatically
   set the counter during allocation in the Linux kernel:
 
   .. code-block:: c
@@ -368,11 +408,11 @@ Non-comprehensive list of changes in this release
   The flexible array member (FAM) can now be accessed immediately without causing
   issues with the sanitizer because the counter is automatically set.
 
-- ``__builtin_reduce_add`` function can now be used in constant expressions.
-- ``__builtin_reduce_mul`` function can now be used in constant expressions.
-- ``__builtin_reduce_and`` function can now be used in constant expressions.
-- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
-- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
+- The following builtins can now be used in constant expressions: ``__builtin_reduce_add``,
+  ``__builtin_reduce_mul``, ``__builtin_reduce_and``, ``__builtin_reduce_or``,
+  ``__builtin_reduce_xor``, ``__builtin_elementwise_popcount``,
+  ``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
+  ``__builtin_elementwise_sub_sat``.
 
 New Compiler Flags
 ------------------
@@ -384,6 +424,12 @@ New Compiler Flags
   existing ``-fno-c++-static-destructors`` flag) skips all static
   destructors registration.
 
+- The ``-Warray-compare`` warning has been added to warn about array comparison
+  on versions older than C++20.
+
+- The ``-Warray-compare-cxx26`` warning has been added to warn about array comparison
+  starting from C++26, this warning is enabled as an error by default.
+
 Deprecated Compiler Flags
 -------------------------
 
@@ -407,10 +453,14 @@ Modified Compiler Flags
   to utilize these vector libraries. The behavior for all other vector function
   libraries remains unchanged.
 
-- The ``-Wnontrivial-memaccess`` warning has been updated to also warn about
-  passing non-trivially-copyable destrination parameter to ``memcpy``,
+- The ``-Wnontrivial-memcall`` warning has been added to warn about
+  passing non-trivially-copyable destination parameter to ``memcpy``,
   ``memset`` and similar functions for which it is a documented undefined
-  behavior.
+  behavior. It is implied by ``-Wnontrivial-memaccess``
+
+- Added ``-fmodules-reduced-bmi`` flag corresponding to
+  ``-fexperimental-modules-reduced-bmi`` flag. The ``-fmodules-reduced-bmi`` flag
+  is intended to be enabled by default in the future.
 
 Removed Compiler Flags
 -------------------------
@@ -444,6 +494,11 @@ Attribute Changes in Clang
 - The ``hybrid_patchable`` attribute is now supported on ARM64EC targets. It can be used to specify
   that a function requires an additional x86-64 thunk, which may be patched at runtime.
 
+- The attribute ``[[clang::no_specializations]]`` has been added to warn
+  users that a specific template shouldn't be specialized. This is useful for
+  e.g. standard library type traits, where adding a specialization results in
+  undefined behaviour.
+
 - ``[[clang::lifetimebound]]`` is now explicitly disallowed on explicit object member functions
   where they were previously silently ignored.
 
@@ -476,6 +531,9 @@ Attribute Changes in Clang
 
 - The ``target_version`` attribute is now only supported for AArch64 and RISC-V architectures.
 
+- Clang now permits the usage of the placement new operator in ``[[msvc::constexpr]]``
+  context outside of the std namespace. (#GH74924)
+
 Improvements to Clang's diagnostics
 -----------------------------------
 
@@ -590,6 +648,22 @@ Improvements to Clang's diagnostics
 
 - Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).
 
+- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).
+
+- Fixed a bug where Clang would not emit ``-Wunused-private-field`` warnings when an unrelated class 
+  defined a defaulted comparison operator (#GH116270).
+
+  .. code-block:: c++
+
+    class A {
+    private:
+      int a; // warning: private field 'a' is not used, no diagnostic previously
+    };
+
+    class C {
+      bool operator==(const C&) = default;
+    };
+
 Improvements to Clang's time-trace
 ----------------------------------
 
@@ -612,6 +686,9 @@ Bug Fixes in This Version
 - Fixed a crash when GNU statement expression contains invalid statement (#GH113468).
 - Fixed a failed assertion when using ``__attribute__((noderef))`` on an
   ``_Atomic``-qualified type (#GH116124).
+- No longer return ``false`` for ``noexcept`` expressions involving a
+  ``delete`` which resolves to a destroying delete but the type of the object
+  being deleted has a potentially throwing destructor (#GH118660).
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -625,6 +702,8 @@ Bug Fixes to Compiler Builtins
 
 - Fix ``__has_builtin`` incorrectly returning ``false`` for some C++ type traits. (#GH111477)
 
+- Fix ``__builtin_source_location`` incorrectly returning wrong column for method chains. (#GH119129)
+
 Bug Fixes to Attribute Support
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -636,7 +715,7 @@ Bug Fixes to C++ Support
 - Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
 - Fix a crash when checking destructor reference with an invalid initializer. (#GH97230)
 - Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
-- Fix a crash when checking the initialzier of an object that was initialized
+- Fix a crash when checking the initializer of an object that was initialized
   with a string literal. (#GH82167)
 - Fix a crash when matching template template parameters with templates which have
   parameters of different class type. (#GH101394)
@@ -680,7 +759,7 @@ Bug Fixes to C++ Support
 - Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
 - A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361), (#GH112352)
 - Fixed a crash in the typo correction of an invalid CTAD guide. (#GH107887)
-- Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter
+- Fixed a crash when clang tries to substitute parameter pack while retaining the parameter
   pack. (#GH63819), (#GH107560)
 - Fix a crash when a static assert declaration has an invalid close location. (#GH108687)
 - Avoided a redundant friend declaration instantiation under a certain ``consteval`` context. (#GH107175)
@@ -719,9 +798,18 @@ Bug Fixes to C++ Support
 - Name independent data members were not correctly initialized from default member initializers. (#GH114069)
 - Fixed expression transformation for ``[[assume(...)]]``, allowing using pack indexing expressions within the
   assumption if they also occur inside of a dependent lambda. (#GH114787)
+- Lambdas now capture function types without considering top-level const qualifiers. (#GH84961)
 - Clang now uses valid deduced type locations when diagnosing functions with trailing return type
   missing placeholder return type. (#GH78694)
 - Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
+- Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385)
+- Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659)
+- Fixed a parser crash when using pack indexing as a nested name specifier. (#GH119072) 
+- Fixed a null pointer dereference issue when heuristically computing ``sizeof...(pack)`` expressions. (#GH81436)
+- Fixed an assertion failure caused by mangled names with invalid identifiers. (#GH112205)
+- Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda
+  captures at the end of a full expression. (#GH115931)
+- Clang no longer rejects deleting a pointer of incomplete enumeration type. (#GH99278)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -733,6 +821,7 @@ Bug Fixes to AST Handling
   and ``relatedalso`` comment commands.
 - Clang now uses the location of the begin of the member expression for ``CallExpr``
   involving deduced ``this``. (#GH116928)
+- Fixed printout of AST that uses pack indexing expression. (#GH116486)
 
 Miscellaneous Bug Fixes
 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -887,9 +976,15 @@ and `-mbulk-memory` flags, which correspond to the [Bulk Memory Operations]
 and [Non-trapping float-to-int Conversions] language features, which are
 [widely implemented in engines].
 
+A new Lime1 target CPU is added, -mcpu=lime1. This CPU follows the definition of
+the Lime1 CPU [here], and enables -mmultivalue, -mmutable-globals,
+-mcall-indirect-overlong, -msign-ext, -mbulk-memory-opt, -mnontrapping-fptoint,
+and -mextended-const.
+
 [Bulk Memory Operations]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
 [Non-trapping float-to-int Conversions]: https://github.com/WebAssembly/spec/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md
 [widely implemented in engines]: https://webassembly.org/features/
+[here]: https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md#lime1
 
 AVR Support
 ^^^^^^^^^^^
@@ -923,6 +1018,14 @@ AST Matchers
 - Ensure ``hasName`` matches template specializations across inline namespaces,
   making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.
 
+- Improved the performance of the ``getExpansionLocOfMacro`` by tracking already processed macros during recursion.
+
+- Add ``exportDecl`` matcher to match export declaration.
+
+- Ensure ``hasType`` and ``hasDeclaration`` match Objective-C interface declarations.
+
+- Ensure ``pointee`` matches Objective-C pointer types.
+
 clang-format
 ------------
 
@@ -974,8 +1077,12 @@ Improvements
 Moved checkers
 ^^^^^^^^^^^^^^
 
+- The checker ``alpha.core.IdenticalExpr`` was deleted because it was
+  duplicated in the clang-tidy checkers ``misc-redundant-expression`` and
+  ``bugprone-branch-clone``.
+
 - The checker ``alpha.security.MallocOverflow`` was deleted because it was
-  badly implemented and its agressive logic produced too many false positives.
+  badly implemented and its aggressive logic produced too many false positives.
   To detect too large arguments passed to malloc, consider using the checker
   ``alpha.taint.TaintedAlloc``.
 
@@ -985,6 +1092,16 @@ Moved checkers
   original checkers were implemented only using AST matching and make more
   sense as a single clang-tidy check.
 
+- The checker ``alpha.unix.Chroot`` was modernized, improved and moved to
+  ``unix.Chroot``. Testing was done on open source projects that use chroot(),
+  and false issues addressed in the improvements based on real use cases. Open
+  source projects used for testing include nsjail, lxroot, dive and ruri.
+  This checker conforms to SEI Cert C recommendation `POS05-C. Limit access to
+  files by creating a jail
+  `_.
+  Fixes (#GH34697).
+  (#GH117791) [Documentation](https://clang.llvm.org/docs/analyzer/checkers.html#unix-chroot-c).
+
 .. _release-notes-sanitizers:
 
 Sanitizers
diff --git a/clang/docs/StandardCPlusPlusModules.rst b/clang/docs/StandardCPlusPlusModules.rst
index 8e22adad15106..93edce0cf90b7 100644
--- a/clang/docs/StandardCPlusPlusModules.rst
+++ b/clang/docs/StandardCPlusPlusModules.rst
@@ -602,16 +602,16 @@ unnecessary dependencies for the BMI. To mitigate the problem, Clang has a
 compiler option to reduce the information contained in the BMI. These two
 formats are known as Full BMI and Reduced BMI, respectively.
 
-Users can use the ``-fexperimental-modules-reduced-bmi`` option to produce a
+Users can use the ``-fmodules-reduced-bmi`` option to produce a
 Reduced BMI.
 
 For the one-phase compilation model (CMake implements this model), with
-``-fexperimental-modules-reduced-bmi``, the generated BMI will be a Reduced
+``-fmodules-reduced-bmi``, the generated BMI will be a Reduced
 BMI automatically. (The output path of the BMI is specified by
 ``-fmodule-output=`` as usual with the one-phase compilation model).
 
 It is also possible to produce a Reduced BMI with the two-phase compilation
-model. When ``-fexperimental-modules-reduced-bmi``, ``--precompile``, and
+model. When ``-fmodules-reduced-bmi``, ``--precompile``, and
 ``-fmodule-output=`` are specified, the generated BMI specified by ``-o`` will
 be a full BMI and the BMI specified by ``-fmodule-output=`` will be a Reduced
 BMI. The dependency graph in this case would look like:
@@ -625,7 +625,7 @@ BMI. The dependency graph in this case would look like:
                                                -> ...
                                                -> consumer_n.cpp
 
-Clang does not emit diagnostics when ``-fexperimental-modules-reduced-bmi`` is
+Clang does not emit diagnostics when ``-fmodules-reduced-bmi`` is
 used with a non-module unit. This design permits users of the one-phase
 compilation model to try using reduced BMIs without needing to modify the build
 system. The two-phase compilation module requires build system support.
@@ -691,11 +691,10 @@ ensure it is reachable, e.g. ``using N::g;``.
 Support for Reduced BMIs is still experimental, but it may become the default
 in the future. The expected roadmap for Reduced BMIs as of Clang 19.x is:
 
-1. ``-fexperimental-modules-reduced-bmi`` is opt-in for 1~2 releases. The period depends
+1. ``-fexperimental-modules-reduced-bmi`` was introduced in v19.x
+2. For v20.x, ``-fmodules-reduced-bmi`` is introduced as an equivalent non-experimental
+   option. It is expected to stay opt-in for 1~2 releases, though the period depends
    on user feedback and may be extended.
-2. Announce that Reduced BMIs are no longer experimental and introduce
-   ``-fmodules-reduced-bmi`` as a new option, and recommend use of the new
-   option. This transition is expected to take 1~2 additional releases as well.
 3. Finally, ``-fmodules-reduced-bmi`` will be the default. When that time
    comes, the term BMI will refer to the Reduced BMI and the Full BMI will only
    be meaningful to build systems which elect to support two-phase compilation.
@@ -814,8 +813,8 @@ With reduced BMI, non-cascading changes can be more powerful. For example,
 
 .. code-block:: console
 
-  $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm  -fexperimental-modules-reduced-bmi -o A.o
-  $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm  -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
+  $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm  -fmodules-reduced-bmi -o A.o
+  $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm  -fmodules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
   $ md5sum B.pcm
   6c2bd452ca32ab418bf35cd141b060b9  B.pcm
 
@@ -831,8 +830,8 @@ and recompile the example:
 
 .. code-block:: console
 
-  $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm  -fexperimental-modules-reduced-bmi -o A.o
-  $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm  -fexperimental-modules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
+  $ clang++ -std=c++20 A.cppm -c -fmodule-output=A.pcm  -fmodules-reduced-bmi -o A.o
+  $ clang++ -std=c++20 B.cppm -c -fmodule-output=B.pcm  -fmodules-reduced-bmi -o B.o -fmodule-file=A=A.pcm
   $ md5sum B.pcm
   6c2bd452ca32ab418bf35cd141b060b9  B.pcm
 
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 2ef603d64557f..8af9f5be644a0 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1059,6 +1059,17 @@ In this way, the user may only need to specify a root configuration file with
     -L /lib
     -T /ldscripts/link.ld
 
+Usually, config file options are placed before command-line options, regardless
+of the actual operation to be performed. The exception is being made for the
+options prefixed with the ``$`` character. These will be used only when linker
+is being invoked, and added after all of the command-line specified linker
+inputs. Here is some example of ``$``-prefixed options:
+
+::
+
+    $-Wl,-Bstatic $-lm
+    $-Wl,-Bshared
+
 Language and Target-Independent Features
 ========================================
 
@@ -2660,7 +2671,7 @@ usual build cycle when using sample profilers for optimization:
 
      > clang-cl /O2 -gdwarf -gline-tables-only ^
        /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^
-       /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf
+       -fprofile-sample-use=code.prof code.cc /Fe:code -fuse-ld=lld /link /debug:dwarf
 
    [OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/
    edge counters. The profile inference algorithm (profi) can be used to infer
@@ -2679,7 +2690,7 @@ usual build cycle when using sample profilers for optimization:
 
      > clang-cl /clang:-fsample-profile-use-profi /O2 -gdwarf -gline-tables-only ^
        /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^
-       /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf
+       -fprofile-sample-use=code.prof code.cc /Fe:code -fuse-ld=lld /link /debug:dwarf
 
 Sample Profile Formats
 """"""""""""""""""""""
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index f34b25cd04bd1..29d5e1f92a69c 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -1750,6 +1750,37 @@ Critical section handling functions modeled by this checker:
    }
  }
 
+.. _unix-Chroot:
+
+unix.Chroot (C)
+"""""""""""""""
+Check improper use of chroot described by SEI Cert C recommendation `POS05-C.
+Limit access to files by creating a jail
+`_.
+The checker finds usage patterns where ``chdir("/")`` is not called immediately
+after a call to ``chroot(path)``.
+
+.. code-block:: c
+
+ void f();
+
+ void test_bad() {
+   chroot("/usr/local");
+   f(); // warn: no call of chdir("/") immediately after chroot
+ }
+
+  void test_bad_path() {
+    chroot("/usr/local");
+    chdir("/usr"); // warn: no call of chdir("/") immediately after chroot
+    f();
+  }
+
+ void test_good() {
+   chroot("/usr/local");
+   chdir("/"); // no warning
+   f();
+ }
+
 .. _unix-Errno:
 
 unix.Errno (C)
@@ -1899,6 +1930,29 @@ Check the size argument passed into C string functions for common erroneous patt
      // warn: potential buffer overflow
  }
 
+.. _unix-cstring-NotNullTerminated:
+
+unix.cstring.NotNullTerminated (C)
+""""""""""""""""""""""""""""""""""
+Check for arguments which are not null-terminated strings;
+applies to the ``strlen``, ``strcpy``, ``strcat``, ``strcmp`` family of functions.
+
+Only very fundamental cases are detected where the passed memory block is
+absolutely different from a null-terminated string. This checker does not
+find if a memory buffer is passed where the terminating zero character
+is missing.
+
+.. code-block:: c
+
+ void test1() {
+   int l = strlen((char *)&test1); // warn
+ }
+
+ void test2() {
+ label:
+   int l = strlen((char *)&&label); // warn
+ }
+
 .. _unix-cstring-NullArg:
 
 unix.cstring.NullArg (C)
@@ -2788,36 +2842,6 @@ Check for assignment of a fixed address to a pointer.
    p = (int *) 0x10000; // warn
  }
 
-.. _alpha-core-IdenticalExpr:
-
-alpha.core.IdenticalExpr (C, C++)
-"""""""""""""""""""""""""""""""""
-Warn about unintended use of identical expressions in operators.
-
-.. code-block:: cpp
-
- // C
- void test() {
-   int a = 5;
-   int b = a | 4 | a; // warn: identical expr on both sides
- }
-
- // C++
- bool f(void);
-
- void test(bool b) {
-   int i = 10;
-   if (f()) { // warn: true and false branches are identical
-     do {
-       i--;
-     } while (f());
-   } else {
-     do {
-       i--;
-     } while (f());
-   }
- }
-
 .. _alpha-core-PointerArithm:
 
 alpha.core.PointerArithm (C)
@@ -3275,21 +3299,6 @@ SEI CERT checkers which tries to find errors based on their `C coding rules (base); // ERROR
+    }
+
+For all cast operations (C-style casts, static_cast, reinterpret_cast, dynamic_cast), if the source type a `Base*` and the destination type is `Derived*`, where `Derived` inherits from `Base`, the static analyzer should signal an error.
+
+This applies to:
+
+- C structs, C++ structs and classes, and Objective-C classes and protocols.
+- Pointers and references.
+- Inside template instantiations and macro expansions that are visible to the compiler.
+
+For types like this, instead of using built in casts, the programmer will use helper functions that internally perform the appropriate type check and disable static analysis.
+
 alpha.webkit.NoUncheckedPtrMemberChecker
 """"""""""""""""""""""""""""""""""""""""
 Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed.
diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py
index 705ff0d4d4098..b6f00657ec914 100755
--- a/clang/docs/tools/dump_ast_matchers.py
+++ b/clang/docs/tools/dump_ast_matchers.py
@@ -5,6 +5,7 @@
 
 import collections
 import re
+import os
 
 try:
     from urllib.request import urlopen
@@ -18,7 +19,11 @@
     CLASS_INDEX_PAGE = None
     print("Unable to get %s: %s" % (CLASS_INDEX_PAGE_URL, e))
 
-MATCHERS_FILE = "../../include/clang/ASTMatchers/ASTMatchers.h"
+CURRENT_DIR = os.path.dirname(__file__)
+MATCHERS_FILE = os.path.join(
+    CURRENT_DIR, "../../include/clang/ASTMatchers/ASTMatchers.h"
+)
+HTML_FILE = os.path.join(CURRENT_DIR, "../LibASTMatchersReference.html")
 
 # Each matcher is documented in one row of the form:
 #   result | name | argA
@@ -590,7 +595,7 @@ def sort_table(matcher_type, matcher_map):
 narrowing_matcher_table = sort_table("NARROWING", narrowing_matchers)
 traversal_matcher_table = sort_table("TRAVERSAL", traversal_matchers)
 
-reference = open("../LibASTMatchersReference.html").read()
+reference = open(HTML_FILE).read()
 reference = re.sub(
     r"",
     node_matcher_table,
diff --git a/clang/docs/tools/dump_format_help.py b/clang/docs/tools/dump_format_help.py
index 1a9afde1b9db9..baf90048ee135 100755
--- a/clang/docs/tools/dump_format_help.py
+++ b/clang/docs/tools/dump_format_help.py
@@ -2,6 +2,7 @@
 # A tool to parse the output of `clang-format --help` and update the
 # documentation in ../ClangFormat.rst automatically.
 
+import argparse
 import os
 import re
 import subprocess
@@ -26,7 +27,7 @@ def indent(text, columns, indent_first_line=True):
 
 
 def get_help_output():
-    args = ["clang-format", "--help"]
+    args = [binary, "--help"]
     cmd = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     out, _ = cmd.communicate()
     out = out.decode(sys.stdout.encoding)
@@ -54,13 +55,22 @@ def validate(text, columns):
             print("warning: line too long:\n", line, file=sys.stderr)
 
 
+p = argparse.ArgumentParser()
+p.add_argument("-d", "--directory", help="directory of clang-format")
+p.add_argument("-o", "--output", help="path of output file")
+opts = p.parse_args()
+
+binary = "clang-format"
+if opts.directory:
+    binary = opts.directory + "/" + binary
+
 help_text = get_help_text()
 validate(help_text, 100)
 
-with open(DOC_FILE) as f:
+with open(DOC_FILE, encoding="utf-8") as f:
     contents = f.read()
 
 contents = substitute(contents, "FORMAT_HELP", help_text)
 
-with open(DOC_FILE, "wb") as output:
+with open(opts.output if opts.output else DOC_FILE, "wb") as output:
     output.write(contents.encode())
diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py
index af0e658fcdc55..f00f3ee8b20e8 100755
--- a/clang/docs/tools/dump_format_style.py
+++ b/clang/docs/tools/dump_format_style.py
@@ -3,6 +3,7 @@
 # documentation in ../ClangFormatStyleOptions.rst automatically.
 # Run from the directory in which this file is located to update the docs.
 
+import argparse
 import inspect
 import os
 import re
@@ -20,7 +21,7 @@
 PLURALS_FILE = os.path.join(os.path.dirname(__file__), "plurals.txt")
 
 plurals: Set[str] = set()
-with open(PLURALS_FILE, "a+") as f:
+with open(PLURALS_FILE) as f:
     f.seek(0)
     plurals = set(f.read().splitlines())
 
@@ -474,6 +475,10 @@ class State:
         return options
 
 
+p = argparse.ArgumentParser()
+p.add_argument("-o", "--output", help="path of output file")
+args = p.parse_args()
+
 with open(FORMAT_STYLE_FILE) as f:
     opts = OptionsReader(f).read_options()
 with open(INCLUDE_STYLE_FILE) as f:
@@ -487,5 +492,5 @@ class State:
 
 contents = substitute(contents, "FORMAT_STYLE_OPTIONS", options_text)
 
-with open(DOC_FILE, "wb") as output:
+with open(args.output if args.output else DOC_FILE, "wb") as output:
     output.write(contents.encode())
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index ff374ad3ada06..9c01978fd49ef 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -542,6 +542,9 @@ class FunctionInfo : public CommonEntityInfo {
   /// The result type of this function, as a C type.
   std::string ResultType;
 
+  /// Ownership convention for return value
+  std::string SwiftReturnOwnership;
+
   /// The function parameters.
   std::vector Params;
 
@@ -622,7 +625,8 @@ inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
          LHS.NumAdjustedNullable == RHS.NumAdjustedNullable &&
          LHS.NullabilityPayload == RHS.NullabilityPayload &&
          LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params &&
-         LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
+         LHS.RawRetainCountConvention == RHS.RawRetainCountConvention &&
+         LHS.SwiftReturnOwnership == RHS.SwiftReturnOwnership;
 }
 
 inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index e4a7957bfa775..cfb093fb39954 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -245,7 +245,11 @@ class ASTContext : public RefCountedBase {
   mutable llvm::FoldingSet ObjCObjectPointerTypes;
   mutable llvm::FoldingSet
     DependentUnaryTransformTypes;
-  mutable llvm::ContextualFoldingSet AutoTypes;
+  // An AutoType can have a dependency on another AutoType via its template
+  // arguments. Since both dependent and dependency are on the same set,
+  // we can end up in an infinite recursion when looking for a node if we used
+  // a `FoldingSet`, since both could end up in the same bucket.
+  mutable llvm::DenseMap AutoTypes;
   mutable llvm::FoldingSet
     DeducedTemplateSpecializationTypes;
   mutable llvm::FoldingSet AtomicTypes;
diff --git a/clang/include/clang/AST/AttrIterator.h b/clang/include/clang/AST/AttrIterator.h
index 66571e1cf0b8e..7e2bb0381d4c8 100644
--- a/clang/include/clang/AST/AttrIterator.h
+++ b/clang/include/clang/AST/AttrIterator.h
@@ -14,11 +14,13 @@
 #define LLVM_CLANG_AST_ATTRITERATOR_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ADL.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Casting.h"
 #include 
 #include 
 #include 
+#include 
 
 namespace clang {
 
@@ -113,13 +115,13 @@ inline bool hasSpecificAttr(const Container& container) {
           specific_attr_end(container);
 }
 template 
-inline SpecificAttr *getSpecificAttr(const Container& container) {
-  specific_attr_iterator i =
-      specific_attr_begin(container);
-  if (i != specific_attr_end(container))
-    return *i;
-  else
-    return nullptr;
+inline auto *getSpecificAttr(const Container &container) {
+  using ValueTy = llvm::detail::ValueOfRange;
+  using ValuePointeeTy = std::remove_pointer_t;
+  using IterTy = std::conditional_t,
+                                    const SpecificAttr, SpecificAttr>;
+  auto It = specific_attr_begin(container);
+  return It != specific_attr_end(container) ? *It : nullptr;
 }
 
 } // namespace clang
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 2693cc0e95b4b..e389b5cd6df5b 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -890,6 +890,13 @@ class CXXRecordDecl : public RecordDecl {
             needsOverloadResolutionForDestructor()) &&
            "destructor should not be deleted");
     data().DefaultedDestructorIsDeleted = true;
+    // C++23 [dcl.constexpr]p3.2:
+    //   if the function is a constructor or destructor, its class does not have
+    //   any virtual base classes.
+    // C++20 [dcl.constexpr]p5:
+    //   The definition of a constexpr destructor whose function-body is
+    //   not = delete shall additionally satisfy...
+    data().DefaultedDestructorIsConstexpr = data().NumVBases == 0;
   }
 
   /// Determine whether this class should get an implicit move
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index e4bf54c3d77b7..dd92d40b80423 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -735,6 +735,7 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   }
 
   void anchor() override;
+
 protected:
   template  struct SpecEntryTraits {
     using DeclType = EntryType;
@@ -775,13 +776,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
     return SpecIterator(isEnd ? Specs.end() : Specs.begin());
   }
 
-  void loadLazySpecializationsImpl() const;
+  void loadLazySpecializationsImpl(bool OnlyPartial = false) const;
+
+  bool loadLazySpecializationsImpl(llvm::ArrayRef Args,
+                                   TemplateParameterList *TPL = nullptr) const;
 
   template 
   typename SpecEntryTraits::DeclType*
   findSpecializationImpl(llvm::FoldingSetVector &Specs,
                          void *&InsertPos, ProfileArguments &&...ProfileArgs);
 
+  template 
+  typename SpecEntryTraits::DeclType *
+  findSpecializationLocally(llvm::FoldingSetVector &Specs,
+                            void *&InsertPos,
+                            ProfileArguments &&...ProfileArgs);
+
   template 
   void addSpecializationImpl(llvm::FoldingSetVector &Specs,
                              EntryType *Entry, void *InsertPos);
@@ -796,13 +806,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
     /// was explicitly specialized.
     llvm::PointerIntPair
         InstantiatedFromMember;
-
-    /// If non-null, points to an array of specializations (including
-    /// partial specializations) known only by their external declaration IDs.
-    ///
-    /// The first value in the array is the number of specializations/partial
-    /// specializations that follow.
-    GlobalDeclID *LazySpecializations = nullptr;
   };
 
   /// Pointer to the common data shared by all declarations of this
@@ -2283,7 +2286,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
   friend class TemplateDeclInstantiator;
 
   /// Load any lazily-loaded specializations from the external source.
-  void LoadLazySpecializations() const;
+  void LoadLazySpecializations(bool OnlyPartial = false) const;
 
   /// Get the underlying class declarations of the template.
   CXXRecordDecl *getTemplatedDecl() const {
@@ -3033,7 +3036,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
   friend class ASTDeclWriter;
 
   /// Load any lazily-loaded specializations from the external source.
-  void LoadLazySpecializations() const;
+  void LoadLazySpecializations(bool OnlyPartial = false) const;
 
   /// Get the underlying variable declarations of the template.
   VarDecl *getTemplatedDecl() const {
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 582ed7c65f58c..9f968ba05b446 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -152,6 +152,21 @@ class ExternalASTSource : public RefCountedBase {
   virtual bool
   FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
 
+  /// Load all the external specializations for the Decl \param D if \param
+  /// OnlyPartial is false. Otherwise, load all the external **partial**
+  /// specializations for the \param D.
+  ///
+  /// Return true if any new specializations get loaded. Return false otherwise.
+  virtual bool LoadExternalSpecializations(const Decl *D, bool OnlyPartial);
+
+  /// Load all the specializations for the Decl \param D with the same template
+  /// args specified by \param TemplateArgs.
+  ///
+  /// Return true if any new specializations get loaded. Return false otherwise.
+  virtual bool
+  LoadExternalSpecializations(const Decl *D,
+                              ArrayRef TemplateArgs);
+
   /// Ensures that the table of all visible declarations inside this
   /// context is up to date.
   ///
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 5ad4c336b6c53..2588c3f645c02 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -483,6 +483,14 @@ class OpenACCGangClause final
     return {getGangKind(I), getExprs()[I]};
   }
 
+  bool hasExprOfKind(OpenACCGangKind GK) const {
+    for (unsigned I = 0; I < getNumExprs(); ++I) {
+      if (getGangKind(I) == GK)
+        return true;
+    }
+    return false;
+  }
+
   static OpenACCGangClause *
   Create(const ASTContext &Ctx, SourceLocation BeginLoc,
          SourceLocation LParenLoc, ArrayRef GangKinds,
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 8068372154225..e306325a698bf 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -3764,6 +3764,8 @@ class ArrayParameterType : public ConstantArrayType {
   static bool classof(const Type *T) {
     return T->getTypeClass() == ArrayParameter;
   }
+
+  QualType getConstantArrayType(const ASTContext &Ctx) const;
 };
 
 /// Represents a C array with an unspecified size.  For example 'int A[]' has
@@ -6561,7 +6563,7 @@ class DeducedType : public Type {
 
 /// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
 /// by a type-constraint.
-class AutoType : public DeducedType, public llvm::FoldingSetNode {
+class AutoType : public DeducedType {
   friend class ASTContext; // ASTContext creates these
 
   ConceptDecl *TypeConstraintConcept;
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 4bcaa953a61af..897aa25dc95cc 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1236,6 +1236,17 @@ AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
 extern const internal::VariadicDynCastAllOfMatcher autoreleasePoolStmt;
 
+/// Matches any export declaration.
+///
+/// Example matches following declarations.
+/// \code
+///   export void foo();
+///   export { void foo(); }
+///   export namespace { void foo(); }
+///   export int v;
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher exportDecl;
+
 /// Matches any value declaration.
 ///
 /// Example matches A, B, C and F
@@ -4033,7 +4044,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
     hasType,
     AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
-                                    CXXBaseSpecifier),
+                                    CXXBaseSpecifier, ObjCInterfaceDecl),
     internal::Matcher, InnerMatcher, 1) {
   QualType QT = internal::getUnderlyingType(Node);
   if (!QT.isNull())
@@ -7434,7 +7445,8 @@ extern const AstTypeMatcher rValueReferenceType;
 AST_TYPELOC_TRAVERSE_MATCHER_DECL(
     pointee, getPointee,
     AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
-                                    PointerType, ReferenceType));
+                                    PointerType, ReferenceType,
+                                    ObjCObjectPointerType));
 
 /// Matches typedef types.
 ///
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index ab8b146453e76..04804d5def046 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -161,6 +161,9 @@ inline QualType getUnderlyingType(const FriendDecl &Node) {
 inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
   return Node.getType();
 }
+inline QualType getUnderlyingType(const ObjCInterfaceDecl &Node) {
+  return Node.getTypeForDecl()->getPointeeType();
+}
 
 /// Unifies obtaining a `TypeSourceInfo` from different node types.
 template  {
     return matchesDecl(Node.getDecl(), Finder, Builder);
   }
 
+  bool matchesSpecialized(const ObjCInterfaceDecl &Node, ASTMatchFinder *Finder,
+                          BoundNodesTreeBuilder *Builder) const {
+    return matchesDecl(Node.getCanonicalDecl(), Finder, Builder);
+  }
+
   /// Extracts the operator new of the new call and returns whether the
   /// inner matcher matches on it.
   bool matchesSpecialized(const CXXNewExpr &Node,
@@ -1213,7 +1221,7 @@ using HasDeclarationSupportedTypes =
              ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
              MemberExpr, QualType, RecordType, TagType,
              TemplateSpecializationType, TemplateTypeParmType, TypedefType,
-             UnresolvedUsingType, ObjCIvarRefExpr>;
+             UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;
 
 /// A Matcher that allows binding the node it matches to an id.
 ///
diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
index 6294c810626a7..8c7ee86d15c06 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
@@ -146,6 +146,10 @@ struct ReferencedDecls {
   /// Free functions and member functions which are referenced (but not
   /// necessarily called).
   llvm::DenseSet Functions;
+  /// When analyzing a lambda's call operator, the set of all parameters (from
+  /// the surrounding function) that the lambda captures. Captured local
+  /// variables are already included in `Locals` above.
+  llvm::DenseSet LambdaCapturedParams;
 };
 
 /// Returns declarations that are declared in or referenced from `FD`.
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fe8175fb249b4..0995d966eaa60 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -55,6 +55,9 @@ class Documentation {
   // When set, specifies that the attribute is deprecated and can optionally
   // specify a replacement attribute.
   DocDeprecated Deprecated;
+
+  // When set, specifies a label that can be used to reference the documentation.
+  string Label = "";
 }
 
 // Specifies that the attribute is explicitly omitted from the documentation,
@@ -103,6 +106,9 @@ def NonParmVar : SubsetSubjecthasLocalStorage()}],
                                 "variables with non-local storage">;
+def VarTmpl : SubsetSubjectgetDescribedVarTemplate()}],
+                            "variable templates">;
+
 def NonBitField : SubsetSubjectisBitField()}],
                                 "non-bit-field non-static data members">;
@@ -4284,33 +4290,28 @@ def Target : InheritableAttr {
   let Subjects = SubjectList<[Function], ErrorDiag>;
   let Documentation = [TargetDocs];
   let AdditionalMembers = [{
-    StringRef getArchitecture() const {
+    std::optional getX86Architecture() const {
       StringRef Features = getFeaturesStr();
-      if (Features == "default") return {};
-
-      SmallVector AttrFeatures;
-      Features.split(AttrFeatures, ",");
-
-      for (auto &Feature : AttrFeatures) {
+      SmallVector AttrFeatures;
+      Features.split(AttrFeatures, ',');
+      for (StringRef Feature : AttrFeatures) {
         Feature = Feature.trim();
         if (Feature.starts_with("arch="))
           return Feature.drop_front(sizeof("arch=") - 1);
       }
-      return "";
+      return std::nullopt;
     }
 
     // Gets the list of features as simple string-refs with no +/- or 'no-'.
     // Only adds the items to 'Out' that are additions.
-    void getAddedFeatures(llvm::SmallVectorImpl &Out) const {
+    void getX86AddedFeatures(llvm::SmallVectorImpl &Out) const {
+      if (isDefaultVersion())
+        return;
       StringRef Features = getFeaturesStr();
-      if (Features == "default") return;
-
-      SmallVector AttrFeatures;
-      Features.split(AttrFeatures, ",");
-
+      SmallVector AttrFeatures;
+      Features.split(AttrFeatures, ',');
       for (auto &Feature : AttrFeatures) {
         Feature = Feature.trim();
-
         if (!Feature.starts_with("no-") && !Feature.starts_with("arch=") &&
             !Feature.starts_with("fpmath=") && !Feature.starts_with("tune="))
           Out.push_back(Feature);
@@ -4328,17 +4329,17 @@ def TargetVersion : InheritableAttr, TargetSpecificAttr &Out) const {
-      if (isDefaultVersion()) return;
-      StringRef Features = getName();
 
-      SmallVector AttrFeatures;
-      Features.split(AttrFeatures, "+");
+    bool isDefaultVersion() const { return getName() == "default"; }
 
-      for (auto &Feature : AttrFeatures) {
+    void getFeatures(llvm::SmallVectorImpl &Out,
+                     char Delim = '+') const {
+      if (isDefaultVersion())
+        return;
+      StringRef Features = getName();
+      SmallVector AttrFeatures;
+      Features.split(AttrFeatures, Delim);
+      for (StringRef Feature : AttrFeatures) {
         Feature = Feature.trim();
         Out.push_back(Feature);
       }
@@ -4355,20 +4356,40 @@ def TargetClones : InheritableAttr {
     StringRef getFeatureStr(unsigned Index) const {
       return *(featuresStrs_begin() + Index);
     }
+
     bool isDefaultVersion(unsigned Index) const {
       return getFeatureStr(Index) == "default";
     }
+
     void getFeatures(llvm::SmallVectorImpl &Out,
-                     unsigned Index) const {
-      if (isDefaultVersion(Index)) return;
+                     unsigned Index, char Delim = '+') const {
+      if (isDefaultVersion(Index))
+        return;
       StringRef Features = getFeatureStr(Index);
-      SmallVector AttrFeatures;
-      Features.split(AttrFeatures, "+");
-      for (auto &Feature : AttrFeatures) {
+      SmallVector AttrFeatures;
+      Features.split(AttrFeatures, Delim);
+      for (StringRef Feature : AttrFeatures) {
         Feature = Feature.trim();
         Out.push_back(Feature);
       }
     }
+
+    std::optional getX86Architecture(unsigned Index) const {
+      StringRef Feature = getFeatureStr(Index);
+      if (Feature.starts_with("arch="))
+        return Feature.drop_front(sizeof("arch=") - 1);
+      return std::nullopt;
+    }
+
+    void getX86Feature(llvm::SmallVectorImpl &Out,
+                       unsigned Index) const {
+      if (isDefaultVersion(Index))
+        return;
+      if (getX86Architecture(Index))
+        return;
+      Out.push_back(getFeatureStr(Index));
+    }
+
     // Given an index into the 'featuresStrs' sequence, compute a unique
     // ID to be used with function name mangling for the associated variant.
     // This mapping is necessary due to a requirement that the mangling ID
@@ -4452,6 +4473,15 @@ def DiagnoseIf : InheritableAttr {
   let Documentation = [DiagnoseIfDocs];
 }
 
+def NoSpecializations : InheritableAttr {
+  let Spellings = [Clang<"no_specializations", /*AllowInC*/0>];
+  let Args = [StringArgument<"Message", 1>];
+  let Subjects = SubjectList<[ClassTmpl, FunctionTmpl, VarTmpl]>;
+  let Documentation = [NoSpecializationsDocs];
+  let MeaningfulToClassTemplateDefinition = 1;
+  let TemplateDependent = 1;
+}
+
 def ArcWeakrefUnavailable : InheritableAttr {
   let Spellings = [Clang<"objc_arc_weak_reference_unavailable">];
   let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
@@ -5645,6 +5675,13 @@ def HLSLNumThreads: InheritableAttr {
   let Documentation = [NumThreadsDocs];
 }
 
+def HLSLSV_GroupThreadID: HLSLAnnotationAttr {
+  let Spellings = [HLSLAnnotation<"SV_GroupThreadID">];
+  let Subjects = SubjectList<[ParmVar, Field]>;
+  let LangOpts = [HLSL];
+  let Documentation = [HLSLSV_GroupThreadIDDocs];
+}
+
 def HLSLSV_GroupID: HLSLAnnotationAttr {
   let Spellings = [HLSLAnnotation<"SV_GroupID">];
   let Subjects = SubjectList<[ParmVar, Field]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index c59c6371ab225..2861dbcf73156 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -1208,6 +1208,15 @@ Query for this feature with ``__has_attribute(diagnose_if)``.
   }];
 }
 
+def NoSpecializationsDocs : Documentation {
+  let Category = DocCatDecl;
+  let Content = [{
+``[[clang::no_specializations]]`` can be applied to function, class, or variable
+templates which should not be explicitly specialized by users. This is primarily
+used to diagnose user specializations of standard library type traits.
+  }];
+}
+
 def PassObjectSizeDocs : Documentation {
   let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
   let Heading = "pass_object_size, pass_dynamic_object_size";
@@ -4982,9 +4991,8 @@ def NoSanitizeAddressDocs : Documentation {
   // This function has multiple distinct spellings, and so it requires a custom
   // heading to be specified. The most common spelling is sufficient.
   let Heading = "no_sanitize_address, no_address_safety_analysis";
+  let Label = "langext-address_sanitizer";
   let Content = [{
-.. _langext-address_sanitizer:
-
 Use ``__attribute__((no_sanitize_address))`` on a function or a global
 variable declaration to specify that address safety instrumentation
 (e.g. AddressSanitizer) should not be applied.
@@ -4994,9 +5002,8 @@ variable declaration to specify that address safety instrumentation
 def NoSanitizeThreadDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "no_sanitize_thread";
+  let Label = "langext-thread_sanitizer";
   let Content = [{
-.. _langext-thread_sanitizer:
-
 Use ``__attribute__((no_sanitize_thread))`` on a function declaration to
 specify that checks for data races on plain (non-atomic) memory accesses should
 not be inserted by ThreadSanitizer. The function is still instrumented by the
@@ -5007,9 +5014,8 @@ tool to avoid false positives and provide meaningful stack traces.
 def NoSanitizeMemoryDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "no_sanitize_memory";
+  let Label = "langext-memory_sanitizer";
   let Content = [{
-.. _langext-memory_sanitizer:
-
 Use ``__attribute__((no_sanitize_memory))`` on a function declaration to
 specify that checks for uninitialized memory should not be inserted
 (e.g. by MemorySanitizer). The function may still be instrumented by the tool
@@ -5020,9 +5026,8 @@ to avoid false positives in other places.
 def CFICanonicalJumpTableDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "cfi_canonical_jump_table";
+  let Label = "langext-cfi_canonical_jump_table";
   let Content = [{
-.. _langext-cfi_canonical_jump_table:
-
 Use ``__attribute__((cfi_canonical_jump_table))`` on a function declaration to
 make the function's CFI jump table canonical. See :ref:`the CFI documentation
 ` for more details.
@@ -5607,6 +5612,8 @@ The capturing entity ``X`` can be one of the following:
       std::set s;
     };
 
+  Note: When applied to a constructor parameter, `[[clang::lifetime_capture_by(this)]]` is just an alias of `[[clang::lifetimebound]]`.
+
 - `global`, `unknown`.
 
   .. code-block:: c++
@@ -9657,6 +9664,17 @@ randomized.
   }];
 }
 
+def HLSLSV_GroupThreadIDDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``SV_GroupThreadID`` semantic, when applied to an input parameter, specifies which
+individual thread within a thread group is executing in. This attribute is
+only supported in compute shaders.
+
+The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupthreadid
+  }];
+}
+
 def HLSLSV_GroupIDDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h
index 714e584ef0d01..f91b2d551ecf2 100644
--- a/clang/include/clang/Basic/Builtins.h
+++ b/clang/include/clang/Basic/Builtins.h
@@ -56,6 +56,7 @@ struct HeaderDesc {
 #undef HEADER
   } ID;
 
+  constexpr HeaderDesc() : ID() {}
   constexpr HeaderDesc(HeaderID ID) : ID(ID) {}
 
   const char *getName() const;
@@ -69,14 +70,140 @@ enum ID {
   FirstTSBuiltin
 };
 
+// The info used to represent each builtin.
 struct Info {
-  llvm::StringLiteral Name;
-  const char *Type, *Attributes;
-  const char *Features;
+  // Rather than store pointers to the string literals describing these four
+  // aspects of builtins, we store offsets into a common string table.
+  struct StrOffsets {
+    int Name;
+    int Type;
+    int Attributes;
+    int Features;
+  } Offsets;
+
   HeaderDesc Header;
   LanguageID Langs;
 };
 
+// The storage for `N` builtins. This contains a single pointer to the string
+// table used for these builtins and an array of metadata for each builtin.
+template  struct Storage {
+  const char *StringTable;
+
+  std::array Infos;
+
+  // A constexpr function to construct the storage for a a given string table in
+  // the first argument and an array in the second argument. This is *only*
+  // expected to be used at compile time, we should mark it `consteval` when
+  // available.
+  //
+  // The `Infos` array is particularly special. This function expects an array
+  // of `Info` structs, where the string offsets of each entry refer to the
+  // *sizes* of those strings rather than their offsets, and for the target
+  // string to be in the provided string table at an offset the sum of all
+  // previous string sizes. This function walks the `Infos` array computing the
+  // running sum and replacing the sizes with the actual offsets in the string
+  // table that should be used. This arrangement is designed to make it easy to
+  // expand `.def` and `.inc` files with X-macros to construct both the string
+  // table and the `Info` structs in the arguments to this function.
+  static constexpr Storage Make(const char *Strings,
+                                   std::array Infos) {
+    // Translate lengths to offsets.
+    int Offset = 0;
+    for (auto &I : Infos) {
+      Info::StrOffsets NewOffsets = {};
+      NewOffsets.Name = Offset;
+      Offset += I.Offsets.Name;
+      NewOffsets.Type = Offset;
+      Offset += I.Offsets.Type;
+      NewOffsets.Attributes = Offset;
+      Offset += I.Offsets.Attributes;
+      NewOffsets.Features = Offset;
+      Offset += I.Offsets.Features;
+      I.Offsets = NewOffsets;
+    }
+    return {Strings, Infos};
+  }
+};
+
+// A detail macro used below to emit a string literal that, after string literal
+// concatenation, ends up triggering the `-Woverlength-strings` warning. While
+// the warning is useful in general to catch accidentally excessive strings,
+// here we are creating them intentionally.
+//
+// This relies on a subtle aspect of `_Pragma`: that the *diagnostic* ones don't
+// turn into actual tokens that would disrupt string literal concatenation.
+#ifdef __clang__
+#define CLANG_BUILTIN_DETAIL_STR_TABLE(S)                                      \
+  _Pragma("clang diagnostic push")                                             \
+      _Pragma("clang diagnostic ignored \"-Woverlength-strings\"")             \
+          S _Pragma("clang diagnostic pop")
+#else
+#define CLANG_BUILTIN_DETAIL_STR_TABLE(S) S
+#endif
+
+// A macro that can be used with `Builtins.def` and similar files as an X-macro
+// to add the string arguments to a builtin string table. This is typically the
+// target for the `BUILTIN`, `LANGBUILTIN`, or `LIBBUILTIN` macros in those
+// files.
+#define CLANG_BUILTIN_STR_TABLE(ID, TYPE, ATTRS)                               \
+  CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" /*FEATURE*/ "\0")
+
+// A macro that can be used with target builtin `.def` and `.inc` files as an
+// X-macro to add the string arguments to a builtin string table. this is
+// typically the target for the `TARGET_BUILTIN` macro.
+#define CLANG_TARGET_BUILTIN_STR_TABLE(ID, TYPE, ATTRS, FEATURE)               \
+  CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" FEATURE "\0")
+
+// A macro that can be used with target builtin `.def` and `.inc` files as an
+// X-macro to add the string arguments to a builtin string table. this is
+// typically the target for the `TARGET_HEADER_BUILTIN` macro. We can't delegate
+// to `TARGET_BUILTIN` because the `FEATURE` string changes position.
+#define CLANG_TARGET_HEADER_BUILTIN_STR_TABLE(ID, TYPE, ATTRS, HEADER, LANGS,  \
+                                              FEATURE)                         \
+  CLANG_BUILTIN_DETAIL_STR_TABLE(#ID "\0" TYPE "\0" ATTRS "\0" FEATURE "\0")
+
+// A detail macro used internally to compute the desired string table
+// `StrOffsets` struct for arguments to `Storage::Make`.
+#define CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS)                      \
+  Builtin::Info::StrOffsets {                                                  \
+    sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof("")                       \
+  }
+
+// A detail macro used internally to compute the desired string table
+// `StrOffsets` struct for arguments to `Storage::Make`.
+#define CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE)      \
+  Builtin::Info::StrOffsets {                                                  \
+    sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof(FEATURE)                  \
+  }
+
+// A set of macros that can be used with builtin `.def' files as an X-macro to
+// create an `Info` struct for a particular builtin. It both computes the
+// `StrOffsets` value for the string table (the lengths here, translated to
+// offsets by the Storage::Make function), and the other metadata for each
+// builtin.
+//
+// There is a corresponding macro for each of `BUILTIN`, `LANGBUILTIN`,
+// `LIBBUILTIN`, `TARGET_BUILTIN`, and `TARGET_HEADER_BUILTIN`.
+#define CLANG_BUILTIN_ENTRY(ID, TYPE, ATTRS)                                   \
+  Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS),             \
+                HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define CLANG_LANGBUILTIN_ENTRY(ID, TYPE, ATTRS, LANG)                         \
+  Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS),             \
+                HeaderDesc::NO_HEADER, LANG},
+#define CLANG_LIBBUILTIN_ENTRY(ID, TYPE, ATTRS, HEADER, LANG)                  \
+  Builtin::Info{CLANG_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS),             \
+                HeaderDesc::HEADER, LANG},
+#define CLANG_TARGET_BUILTIN_ENTRY(ID, TYPE, ATTRS, FEATURE)                   \
+  Builtin::Info{                                                               \
+      CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE),       \
+      HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define CLANG_TARGET_HEADER_BUILTIN_ENTRY(ID, TYPE, ATTRS, HEADER, LANG,       \
+                                          FEATURE)                             \
+  Builtin::Info{                                                               \
+      CLANG_TARGET_BUILTIN_DETAIL_STR_OFFSETS(ID, TYPE, ATTRS, FEATURE),       \
+      HeaderDesc::HEADER, LANG},
+
 /// Holds information about both target-independent and
 /// target-specific builtins, allowing easy queries by clients.
 ///
@@ -84,8 +211,11 @@ struct Info {
 /// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to
 /// be translated back with getAuxBuiltinID() before use.
 class Context {
-  llvm::ArrayRef TSRecords;
-  llvm::ArrayRef AuxTSRecords;
+  const char *TSStrTable = nullptr;
+  const char *AuxTSStrTable = nullptr;
+
+  llvm::ArrayRef TSInfos;
+  llvm::ArrayRef AuxTSInfos;
 
 public:
   Context() = default;
@@ -101,12 +231,13 @@ class Context {
 
   /// Return the identifier name for the specified builtin,
   /// e.g. "__builtin_abs".
-  llvm::StringRef getName(unsigned ID) const { return getRecord(ID).Name; }
+  llvm::StringRef getName(unsigned ID) const;
 
   /// Get the type descriptor string for the specified builtin.
-  const char *getTypeString(unsigned ID) const {
-    return getRecord(ID).Type;
-  }
+  const char *getTypeString(unsigned ID) const;
+
+  /// Get the attributes descriptor string for the specified builtin.
+  const char *getAttributesString(unsigned ID) const;
 
   /// Return true if this function is a target-specific builtin.
   bool isTSBuiltin(unsigned ID) const {
@@ -115,40 +246,40 @@ class Context {
 
   /// Return true if this function has no side effects.
   bool isPure(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'U') != nullptr;
+    return strchr(getAttributesString(ID), 'U') != nullptr;
   }
 
   /// Return true if this function has no side effects and doesn't
   /// read memory.
   bool isConst(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'c') != nullptr;
+    return strchr(getAttributesString(ID), 'c') != nullptr;
   }
 
   /// Return true if we know this builtin never throws an exception.
   bool isNoThrow(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'n') != nullptr;
+    return strchr(getAttributesString(ID), 'n') != nullptr;
   }
 
   /// Return true if we know this builtin never returns.
   bool isNoReturn(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'r') != nullptr;
+    return strchr(getAttributesString(ID), 'r') != nullptr;
   }
 
   /// Return true if we know this builtin can return twice.
   bool isReturnsTwice(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'j') != nullptr;
+    return strchr(getAttributesString(ID), 'j') != nullptr;
   }
 
   /// Returns true if this builtin does not perform the side-effects
   /// of its arguments.
   bool isUnevaluated(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'u') != nullptr;
+    return strchr(getAttributesString(ID), 'u') != nullptr;
   }
 
   /// Return true if this is a builtin for a libc/libm function,
   /// with a "__builtin_" prefix (e.g. __builtin_abs).
   bool isLibFunction(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'F') != nullptr;
+    return strchr(getAttributesString(ID), 'F') != nullptr;
   }
 
   /// Determines whether this builtin is a predefined libc/libm
@@ -159,21 +290,21 @@ class Context {
   /// they do not, but they are recognized as builtins once we see
   /// a declaration.
   bool isPredefinedLibFunction(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'f') != nullptr;
+    return strchr(getAttributesString(ID), 'f') != nullptr;
   }
 
   /// Returns true if this builtin requires appropriate header in other
   /// compilers. In Clang it will work even without including it, but we can emit
   /// a warning about missing header.
   bool isHeaderDependentFunction(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'h') != nullptr;
+    return strchr(getAttributesString(ID), 'h') != nullptr;
   }
 
   /// Determines whether this builtin is a predefined compiler-rt/libgcc
   /// function, such as "__clear_cache", where we know the signature a
   /// priori.
   bool isPredefinedRuntimeFunction(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'i') != nullptr;
+    return strchr(getAttributesString(ID), 'i') != nullptr;
   }
 
   /// Determines whether this builtin is a C++ standard library function
@@ -181,7 +312,7 @@ class Context {
   /// specialization, where the signature is determined by the standard library
   /// declaration.
   bool isInStdNamespace(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'z') != nullptr;
+    return strchr(getAttributesString(ID), 'z') != nullptr;
   }
 
   /// Determines whether this builtin can have its address taken with no
@@ -195,33 +326,33 @@ class Context {
 
   /// Determines whether this builtin has custom typechecking.
   bool hasCustomTypechecking(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 't') != nullptr;
+    return strchr(getAttributesString(ID), 't') != nullptr;
   }
 
   /// Determines whether a declaration of this builtin should be recognized
   /// even if the type doesn't match the specified signature.
   bool allowTypeMismatch(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'T') != nullptr ||
+    return strchr(getAttributesString(ID), 'T') != nullptr ||
            hasCustomTypechecking(ID);
   }
 
   /// Determines whether this builtin has a result or any arguments which
   /// are pointer types.
   bool hasPtrArgsOrResult(unsigned ID) const {
-    return strchr(getRecord(ID).Type, '*') != nullptr;
+    return strchr(getTypeString(ID), '*') != nullptr;
   }
 
   /// Return true if this builtin has a result or any arguments which are
   /// reference types.
   bool hasReferenceArgsOrResult(unsigned ID) const {
-    return strchr(getRecord(ID).Type, '&') != nullptr ||
-           strchr(getRecord(ID).Type, 'A') != nullptr;
+    return strchr(getTypeString(ID), '&') != nullptr ||
+           strchr(getTypeString(ID), 'A') != nullptr;
   }
 
   /// If this is a library function that comes from a specific
   /// header, retrieve that header name.
   const char *getHeaderName(unsigned ID) const {
-    return getRecord(ID).Header.getName();
+    return getInfo(ID).Header.getName();
   }
 
   /// Determine whether this builtin is like printf in its
@@ -246,27 +377,25 @@ class Context {
   /// Such functions can be const when the MathErrno lang option and FP
   /// exceptions are disabled.
   bool isConstWithoutErrnoAndExceptions(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'e') != nullptr;
+    return strchr(getAttributesString(ID), 'e') != nullptr;
   }
 
   bool isConstWithoutExceptions(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'g') != nullptr;
+    return strchr(getAttributesString(ID), 'g') != nullptr;
   }
 
-  const char *getRequiredFeatures(unsigned ID) const {
-    return getRecord(ID).Features;
-  }
+  const char *getRequiredFeatures(unsigned ID) const;
 
   unsigned getRequiredVectorWidth(unsigned ID) const;
 
   /// Return true if builtin ID belongs to AuxTarget.
   bool isAuxBuiltinID(unsigned ID) const {
-    return ID >= (Builtin::FirstTSBuiltin + TSRecords.size());
+    return ID >= (Builtin::FirstTSBuiltin + TSInfos.size());
   }
 
   /// Return real builtin ID (i.e. ID it would have during compilation
   /// for AuxTarget).
-  unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSRecords.size(); }
+  unsigned getAuxBuiltinID(unsigned ID) const { return ID - TSInfos.size(); }
 
   /// Returns true if this is a libc/libm function without the '__builtin_'
   /// prefix.
@@ -278,16 +407,20 @@ class Context {
 
   /// Return true if this function can be constant evaluated by Clang frontend.
   bool isConstantEvaluated(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'E') != nullptr;
+    return strchr(getAttributesString(ID), 'E') != nullptr;
   }
 
   /// Returns true if this is an immediate (consteval) function
   bool isImmediate(unsigned ID) const {
-    return strchr(getRecord(ID).Attributes, 'G') != nullptr;
+    return strchr(getAttributesString(ID), 'G') != nullptr;
   }
 
 private:
-  const Info &getRecord(unsigned ID) const;
+  std::pair getStrTableAndInfo(unsigned ID) const;
+
+  const Info &getInfo(unsigned ID) const {
+    return getStrTableAndInfo(ID).second;
+  }
 
   /// Helper function for isPrintfLike and isScanfLike.
   bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg,
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index b48102ff25b3a..b67464f78b4c7 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1270,7 +1270,7 @@ def ElementwiseATan2 : Builtin {
 
 def ElementwiseBitreverse : Builtin {
   let Spellings = ["__builtin_elementwise_bitreverse"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
 
@@ -1450,13 +1450,13 @@ def ElementwiseFma : Builtin {
 
 def ElementwiseAddSat : Builtin {
   let Spellings = ["__builtin_elementwise_add_sat"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
 
 def ElementwiseSubSat : Builtin {
   let Spellings = ["__builtin_elementwise_sub_sat"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
 
@@ -4757,6 +4757,12 @@ def SYCLIsNDRangeKernel : LangBuiltin<"SYCL_LANG"> {
 }
 
 // HLSL
+def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_getpointer"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 def HLSLAll : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_all"];
   let Attributes = [NoThrow, Const];
@@ -4943,6 +4949,12 @@ def HLSLClip: LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLGroupMemoryBarrierWithGroupSync: LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_group_memory_barrier_with_group_sync"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void()";
+}
+
 // Builtins for XRay.
 def XRayCustomEvent : Builtin {
   let Spellings = ["__xray_customevent"];
diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def
index 473b1d4698f04..7933686ffe84e 100644
--- a/clang/include/clang/Basic/BuiltinsAArch64.def
+++ b/clang/include/clang/Basic/BuiltinsAArch64.def
@@ -182,6 +182,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange_rel,   "NiNiD*Ni",    "nh", INTRIN_H,
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf,  "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_acq, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_nf,  "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_rel, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_acq,  "ccD*cc",         "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_nf,   "ccD*cc",         "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
@@ -195,6 +198,8 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel,   "NiNiD*NiNi",     "nh",
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf,  "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_acq, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_rel, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange128,    "UcLLiD*LLiLLiLLi*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange128_acq,"UcLLiD*LLiLLiLLi*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
@@ -281,6 +286,16 @@ TARGET_HEADER_BUILTIN(__readx18word,  "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
 TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 
+TARGET_HEADER_BUILTIN(__addx18byte,  "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18word,  "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__incx18byte,  "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18word,  "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18dword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18qword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+
 TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def
index aa3731461d258..576ca70d27319 100644
--- a/clang/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def
@@ -472,6 +472,8 @@ TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr4_b64_v2i32, "V2iV2i*3", "nc", "gfx950
 TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr6_b96_v3i32, "V3iV3i*3", "nc", "gfx950-insts")
 TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr8_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
 TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4i16, "V4sV4s*3", "nc", "gfx950-insts")
+TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4f16, "V4hV4h*3", "nc", "gfx950-insts")
+TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4bf16, "V4yV4y*3", "nc", "gfx950-insts")
 
 TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_i8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
 TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_u8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
@@ -619,8 +621,8 @@ TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f32, "V6UiV32fUif", "nc
 TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_bf16, "V6UiV32yUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
 TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f16, "V6UiV32hUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
 TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32, "V6UiV32fUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
-TARGET_BUILTIN(__builtin_amdgcn_bitop3_b32, "iiiiIUc", "nc", "bitop3-insts")
-TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUc", "nc", "bitop3-insts")
+TARGET_BUILTIN(__builtin_amdgcn_bitop3_b32, "iiiiIUi", "nc", "bitop3-insts")
+TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUi", "nc", "bitop3-insts")
 
 TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf16_f32, "V2yV2yfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")
 TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_f16_f32, "V2hV2hfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")
diff --git a/clang/include/clang/Basic/BuiltinsARM.def b/clang/include/clang/Basic/BuiltinsARM.def
index 9ee918cb21475..5a7064a98045e 100644
--- a/clang/include/clang/Basic/BuiltinsARM.def
+++ b/clang/include/clang/Basic/BuiltinsARM.def
@@ -270,6 +270,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange_rel,   "NiNiD*Ni",    "nh", INTRIN_H,
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf,  "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_acq, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_nf,  "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_rel, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_acq,  "ccD*cc",         "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_nf,   "ccD*cc",         "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
@@ -283,6 +286,8 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel,   "NiNiD*NiNi",     "nh",
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf,  "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_acq, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_rel, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 
 TARGET_HEADER_BUILTIN(_InterlockedOr8_acq,  "ccD*c",       "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
 TARGET_HEADER_BUILTIN(_InterlockedOr8_nf,   "ccD*c",       "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def
index 161df386f00f0..bb7d54bbb793e 100644
--- a/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/clang/include/clang/Basic/BuiltinsPPC.def
@@ -1138,5 +1138,6 @@ UNALIASED_CUSTOM_BUILTIN(mma_pmxvbf16ger2nn, "vW512*VVi15i15i3", true,
 // FIXME: Obviously incomplete.
 
 #undef BUILTIN
+#undef TARGET_BUILTIN
 #undef CUSTOM_BUILTIN
 #undef UNALIASED_CUSTOM_BUILTIN
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index a9715351726e2..1b90b19cfa769 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -243,7 +243,7 @@ ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Defa
 
 CODEGENOPT(RelaxAll          , 1, 0) ///< Relax all machine code instructions.
 CODEGENOPT(RelaxedAliasing   , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
-CODEGENOPT(PointerTBAA, 1, 0)        ///< Whether or not to use distinct TBAA tags for pointers.
+CODEGENOPT(PointerTBAA       , 1, 1) ///< Whether or not to use distinct TBAA tags for pointers.
 CODEGENOPT(StructPathTBAA    , 1, 0) ///< Whether or not to use struct-path TBAA.
 CODEGENOPT(NewStructPathTBAA , 1, 0) ///< Whether or not to use enhanced struct-path TBAA.
 CODEGENOPT(SaveTempLabels    , 1, 0) ///< Save temporary labels.
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index ef46ac5229ecb..1b8b7153efa65 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -562,7 +562,8 @@ class DiagnosticsEngine : public RefCountedBase {
   ArgToStringFnTy ArgToStringFn;
 
   /// Whether the diagnostic should be suppressed in FilePath.
-  llvm::unique_function
+  llvm::unique_function
       DiagSuppressionMapping;
 
 public:
@@ -978,7 +979,7 @@ class DiagnosticsEngine : public RefCountedBase {
   /// These take presumed locations into account, and can still be overriden by
   /// clang-diagnostics pragmas.
   void setDiagSuppressionMapping(llvm::MemoryBuffer &Input);
-  bool isSuppressedViaMapping(diag::kind DiagId, StringRef FilePath) const;
+  bool isSuppressedViaMapping(diag::kind DiagId, SourceLocation DiagLoc) const;
 
   /// Issue the message to the client.
   ///
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 6a658cf14356f..f630698757c5f 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -782,8 +782,8 @@ def err_module_odr_violation_field : Error<
   "%select{"
   "field %4|"
   "field %4 with type %5|"
-  "%select{non-|}5bitfield %4|"
-  "bitfield %4 with one width expression|"
+  "%select{non-|}5bit-field %4|"
+  "bit-field %4 with one width expression|"
   "%select{non-|}5mutable field %4|"
   "field %4 with %select{no|an}5 initializer|"
   "field %4 with an initializer"
@@ -793,8 +793,8 @@ def note_module_odr_violation_field : Note<
   "%select{"
   "field %3|"
   "field %3 with type %4|"
-  "%select{non-|}4bitfield %3|"
-  "bitfield %3 with different width expression|"
+  "%select{non-|}4bit-field %3|"
+  "bit-field %3 with different width expression|"
   "%select{non-|}4mutable field %3|"
   "field %3 with %select{no|an}4 initializer|"
   "field %3 with a different initializer"
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 30831c1971cc5..e5fa9465f638a 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -213,6 +213,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
                                       [CXX11CompatDeprecatedWritableStr]>;
 def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
 def DeprecatedType : DiagGroup<"deprecated-type">;
+def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
 // FIXME: Why is DeprecatedImplementations not in this group?
 def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedArrayCompare,
@@ -237,7 +238,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedType,
                                           DeprecatedVolatile,
                                           DeprecatedWritableStr,
-                                          DeprecatedRedundantConstexprStaticDef
+                                          DeprecatedRedundantConstexprStaticDef,
+                                          DeprecatedMissingCommaVariadicParam
                                           ]>,
                  DiagCategory<"Deprecations">;
 
@@ -294,11 +296,13 @@ def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
 // Name of this warning in GCC.
 def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;
 
+def VariadicMacroArgumentsOmitted : DiagGroup<"variadic-macro-arguments-omitted">;
+
 // Warnings for C code which is not compatible with previous C standards.
 def CPre11Compat : DiagGroup<"pre-c11-compat">;
 def CPre11CompatPedantic : DiagGroup<"pre-c11-compat-pedantic",
                                      [CPre11Compat]>;
-def CPre23Compat : DiagGroup<"pre-c23-compat">;
+def CPre23Compat : DiagGroup<"pre-c23-compat", [VariadicMacroArgumentsOmitted]>;
 def CPre23CompatPedantic : DiagGroup<"pre-c23-compat-pedantic",
                                      [CPre23Compat]>;
 def : DiagGroup<"pre-c2x-compat", [CPre23Compat]>;
@@ -687,7 +691,8 @@ def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">;
 def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">;
 def MemsetTransposedArgs : DiagGroup<"memset-transposed-args">;
 def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">;
-def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess">;
+def NonTrivialMemcall : DiagGroup<"nontrivial-memcall">;
+def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess", [NonTrivialMemcall]>;
 def SuspiciousBzero : DiagGroup<"suspicious-bzero">;
 def SuspiciousMemaccess : DiagGroup<"suspicious-memaccess",
   [SizeofPointerMemaccess, DynamicClassMemaccess,
@@ -913,7 +918,7 @@ 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 GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments", [VariadicMacroArgumentsOmitted]>;
 def MisleadingIndentation : DiagGroup<"misleading-indentation">;
 def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
 
@@ -1206,7 +1211,7 @@ def CXX17 : DiagGroup<"c++17-extensions", [CXX17Attrs]>;
 
 // A warning group for warnings about using C++20 features as extensions in
 // earlier C++ versions.
-def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator, CXX20Attrs]>;
+def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator, CXX20Attrs, VariadicMacroArgumentsOmitted]>;
 
 // A warning group for warnings about using C++23 features as extensions in
 // earlier C++ versions.
@@ -1233,7 +1238,7 @@ def C11 : DiagGroup<"c11-extensions">;
 def C99 : DiagGroup<"c99-extensions", [C99Designator]>;
 
 // A warning group for warnings about using C23 features as extensions.
-def C23 : DiagGroup<"c23-extensions">;
+def C23 : DiagGroup<"c23-extensions", [VariadicMacroArgumentsOmitted]>;
 
 def : DiagGroup<"c2x-extensions", [C23]>;
 
@@ -1614,4 +1619,3 @@ def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-stor
 
 // A warning for options that enable a feature that is not yet complete
 def ExperimentalOption : DiagGroup<"experimental-option">;
-
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 889370221f32f..959376b084721 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -486,14 +486,14 @@ def ext_embedded_directive : Extension<
   InGroup>;
 def ext_c_missing_varargs_arg : Extension<
   "passing no argument for the '...' parameter of a variadic macro is "
-  "a C23 extension">, InGroup;
+  "a C23 extension">, InGroup;
 def ext_cxx_missing_varargs_arg : Extension<
   "passing no argument for the '...' parameter of a variadic macro is "
-  "a C++20 extension">, InGroup;
+  "a C++20 extension">, InGroup;
 def warn_c17_compat_missing_varargs_arg : Warning<
   "passing no argument for the '...' parameter of a variadic macro is "
   "incompatible with C standards before C23">,
-  InGroup, DefaultIgnore;
+  InGroup, DefaultIgnore;
 def warn_cxx17_compat_missing_varargs_arg : Warning<
   "passing no argument for the '...' parameter of a variadic macro is "
   "incompatible with C++ standards before C++20">,
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 77bf08453dea5..9fa8d5901bd0a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
   "function scope depth exceeded maximum of %0">, DefaultFatal;
 def err_missing_comma_before_ellipsis : Error<
   "C requires a comma prior to the ellipsis in a variadic function type">;
+def warn_deprecated_missing_comma_before_ellipsis : Warning<
+  "declaration of a variadic function without a comma before '...' is deprecated">,
+  InGroup;
 def err_unexpected_typedef_ident : Error<
   "unexpected type name %0: expected identifier">;
 def warn_cxx98_compat_decltype : Warning<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 56226fa5bf4c7..90047b1701598 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -869,7 +869,7 @@ def warn_cstruct_memaccess : Warning<
 def warn_cxxstruct_memaccess : Warning<
   "first argument in call to "
   "%0 is a pointer to non-trivially copyable type %1">,
-  InGroup;
+  InGroup;
 def note_nontrivial_field : Note<
   "field is non-trivial to %select{copy|default-initialize}0">;
 def err_non_trivial_c_union_in_invalid_context : Error<
@@ -5533,6 +5533,10 @@ def note_dependent_function_template_spec_discard_reason : Note<
   "candidate ignored: %select{not a function template|"
   "not a member of the enclosing %select{class template|"
   "namespace; did you mean to explicitly qualify the specialization?}1}0">;
+def warn_invalid_specialization : Warning<
+  "%0 cannot be specialized%select{|: %2}1">,
+  DefaultError, InGroup>;
+def note_marked_here : Note<"marked %0 here">;
 
 // C++ class template specializations and out-of-line definitions
 def err_template_spec_needs_header : Error<
@@ -6358,7 +6362,7 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
 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 %select{C++|SYCL device code}0">;
+  "zero-length arrays are not permitted in %select{C++|SYCL device code|HIP device code}0">;
 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">;
@@ -6505,7 +6509,7 @@ def warn_signed_bitfield_enum_conversion : Warning<
   "enumerators of %1">,
   InGroup, DefaultIgnore;
 def note_change_bitfield_sign : Note<
-  "consider making the bitfield type %select{unsigned|signed}0">;
+  "consider making the bit-field type %select{unsigned|signed}0">;
 
 def warn_missing_braces : Warning<
   "suggest braces around initialization of subobject">,
@@ -6758,14 +6762,15 @@ def warn_counted_by_attr_elt_type_unknown_size :
 // __builtin_counted_by_ref diagnostics:
 def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
   "'__builtin_counted_by_ref' argument must reference a flexible array member">;
+def err_builtin_counted_by_ref_has_side_effects : Error<
+  "'__builtin_counted_by_ref' argument cannot have side-effects">;
+
 def err_builtin_counted_by_ref_cannot_leak_reference : Error<
-  "value returned by '__builtin_counted_by_ref' cannot be assigned to a "
-  "variable, have its address taken, or passed into or returned from a function">;
-def err_builtin_counted_by_ref_invalid_lhs_use : Error<
+  "value returned by '__builtin_counted_by_ref' cannot be %select{assigned to a "
+  "variable|passed into a function|returned from a function}0">;
+def err_builtin_counted_by_ref_invalid_use : Error<
   "value returned by '__builtin_counted_by_ref' cannot be used in "
   "%select{an array subscript|a binary}0 expression">;
-def err_builtin_counted_by_ref_has_side_effects : Error<
-  "'__builtin_counted_by_ref' argument cannot have side-effects">;
 
 let CategoryName = "ARC Semantic Issue" in {
 
@@ -10370,6 +10375,16 @@ def warn_depr_array_comparison : Warning<
   "to compare array addresses, use unary '+' to decay operands to pointers">,
   InGroup;
 
+def warn_array_comparison : Warning<
+  "comparison between two arrays compare their addresses and will be deprecated in c++20; "
+  "to compare array addresses, use unary '+' to decay operands to pointers">,
+  InGroup>;
+
+def warn_array_comparison_cxx26 : Warning<
+  "comparison between two arrays is ill-formed in C++26; "
+  "to compare array addresses, use unary '+' to decay operands to pointers">,
+  InGroup>, DefaultError;
+
 def warn_stringcompare : Warning<
   "result of comparison against %select{a string literal|@encode}0 is "
   "unspecified (use an explicit string comparison function instead)">,
@@ -13000,9 +13015,9 @@ def err_acc_clause_cannot_combine
     : Error<"OpenACC clause '%0' may not appear on the same construct as a "
             "'%1' clause on a '%2' construct">;
 def err_acc_reduction_num_gangs_conflict
-    : Error<
-          "OpenACC 'reduction' clause may not appear on a 'parallel' construct "
-          "with a 'num_gangs' clause with more than 1 argument, have %0">;
+    : Error<"OpenACC '%1' clause %select{|with more than 1 argument }0may not "
+            "appear on a '%2' construct "
+            "with a '%3' clause%select{ with more than 1 argument|}0">;
 def err_acc_reduction_type
     : Error<"OpenACC 'reduction' variable must be of scalar type, sub-array, or a "
             "composite of scalar types;%select{| sub-array base}1 type is %0">;
@@ -13027,48 +13042,50 @@ def err_acc_size_expr_value
           "OpenACC 'tile' clause size expression must be %select{an asterisk "
           "or a constant expression|positive integer value, evaluated to %1}0">;
 def err_acc_invalid_in_loop
-    : Error<"%select{OpenACC '%2' construct|while loop|do loop}0 cannot appear "
-            "in intervening code of a 'loop' with a '%1' clause">;
+    : Error<"%select{OpenACC '%3' construct|while loop|do loop}0 cannot appear "
+            "in intervening code of a '%1' with a '%2' clause">;
 def note_acc_active_clause_here
     : Note<"active '%0' clause defined here">;
 def err_acc_clause_multiple_loops
-    : Error<"more than one for-loop in a loop associated with OpenACC 'loop' "
-            "construct with a '%select{collapse|tile}0' clause">;
+    : Error<"more than one for-loop in a loop associated with OpenACC '%0' "
+            "construct with a '%1' clause">;
 def err_acc_insufficient_loops
     : Error<"'%0' clause specifies a loop count greater than the number "
             "of available loops">;
 def err_acc_intervening_code
     : Error<"inner loops must be tightly nested inside a '%0' clause on "
-            "a 'loop' construct">;
+            "a '%1' construct">;
 def err_acc_gang_multiple_elt
     : Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
             "'num'|'dim'|'static'}0 argument">;
 def err_acc_int_arg_invalid
-    : Error<"'%1' argument on '%0' clause is not permitted on a%select{n "
-            "orphaned|||}2 'loop' construct %select{|associated with a "
-            "'parallel' compute construct|associated with a 'kernels' compute "
-            "construct|associated with a 'serial' compute construct}2">;
+    : Error<"'%0' argument on '%1' clause is not permitted on a%select{|n "
+            "orphaned}2 '%3' construct%select{| associated with a '%5' compute "
+            "construct}4">;
 def err_acc_gang_dim_value
     : Error<"argument to 'gang' clause dimension must be %select{a constant "
             "expression|1, 2, or 3: evaluated to %1}0">;
 def err_acc_num_arg_conflict
-    : Error<"'num' argument to '%0' clause not allowed on a 'loop' construct "
-            "associated with a 'kernels' construct that has a "
-            "'%select{num_gangs|num_workers|vector_length}1' "
-            "clause">;
+    : Error<"'%0' argument to '%1' clause not allowed on a '%2' "
+            "construct%select{| associated with a '%4' construct}3 that has a "
+            "'%5' clause">;
+def err_acc_num_arg_conflict_reverse
+    : Error<"'%0' clause not allowed on a 'kernels loop' construct that "
+            "has a '%1' clause with a%select{n| 'num'}2 argument">;
 def err_acc_clause_in_clause_region
     : Error<"loop with a '%0' clause may not exist in the region of a '%1' "
-            "clause%select{| on a 'kernels' compute construct}2">;
+            "clause%select{| on a '%3' construct}2">;
 def err_acc_gang_reduction_conflict
     : Error<"%select{OpenACC 'gang' clause with a 'dim' value greater than "
             "1|OpenACC 'reduction' clause}0 cannot "
-            "appear on the same 'loop' construct as a %select{'reduction' "
+            "appear on the same '%1' construct as a %select{'reduction' "
             "clause|'gang' clause with a 'dim' value greater than 1}0">;
 def err_acc_gang_reduction_numgangs_conflict
-    : Error<"OpenACC '%0' clause cannot appear on the same 'loop' construct "
-            "as a '%1' clause inside a compute construct with a "
+    : Error<"OpenACC '%0' clause cannot appear on the same '%2' construct as a "
+            "'%1' clause %select{inside a compute construct with a|and a}3 "
             "'num_gangs' clause with more than one argument">;
-def err_reduction_op_mismatch
+
+    def err_reduction_op_mismatch
     : Error<"OpenACC 'reduction' variable must have the same operator in all "
             "nested constructs (%0 vs %1)">;
 def err_acc_loop_variable_type
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 9088c867d53ce..15c59c6bcdf29 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -163,6 +163,8 @@ FEATURE(c_atomic, LangOpts.C11)
 FEATURE(c_generic_selections, LangOpts.C11)
 FEATURE(c_static_assert, LangOpts.C11)
 FEATURE(c_thread_local, LangOpts.C11 &&PP.getTargetInfo().isTLSSupported())
+// C23 features
+FEATURE(c_fixed_enum, LangOpts.C23)
 // C++11 features
 FEATURE(cxx_access_control_sfinae, LangOpts.CPlusPlus11)
 FEATURE(cxx_alias_templates, LangOpts.CPlusPlus11)
@@ -269,6 +271,7 @@ EXTENSION(c_static_assert, true)
 EXTENSION(c_thread_local, PP.getTargetInfo().isTLSSupported())
 // C23 features supported by other languages as extensions
 EXTENSION(c_attributes, true)
+EXTENSION(c_fixed_enum, true)
 // C++11 features supported by other languages as extensions.
 EXTENSION(cxx_atomic, LangOpts.CPlusPlus)
 EXTENSION(cxx_default_function_template_args, LangOpts.CPlusPlus)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 1499101624b9c..8132089f9736b 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -178,6 +178,7 @@ LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
 LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0,
         "incorporate address discrimination in authenticated function pointers in init/fini arrays")
 LANGOPT(PointerAuthELFGOT, 1, 0, "authenticate pointers from GOT")
+LANGOPT(AArch64JumpTableHardening, 1, 0, "use hardened lowering for jump-table dispatch")
 
 LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
 LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index 3deb666b37513..a3a3e50bcde5d 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -172,6 +172,9 @@ struct PointerAuthOptions {
   /// Do indirect goto label addresses need to be authenticated?
   bool IndirectGotos = false;
 
+  /// Use hardened lowering for jump-table dispatch?
+  bool AArch64JumpTableHardening = false;
+
   /// The ABI for C function pointers.
   PointerAuthSchema FunctionPointers;
 
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 89ebf5758a5b5..a14fd2c4b224d 100644
--- a/clang/include/clang/Basic/TargetBuiltins.h
+++ b/clang/include/clang/Basic/TargetBuiltins.h
@@ -336,6 +336,7 @@ namespace clang {
     bool isTupleSet() const { return Flags & IsTupleSet; }
     bool isReadZA() const { return Flags & IsReadZA; }
     bool isWriteZA() const { return Flags & IsWriteZA; }
+    bool setsFPMR() const { return Flags & SetsFPMR; }
     bool isReductionQV() const { return Flags & IsReductionQV; }
     uint64_t getBits() const { return Flags; }
     bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 9cd23d123f2ba..52a1ac9781395 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/BitmaskEnum.h"
+#include "clang/Basic/Builtins.h"
 #include "clang/Basic/CFProtectionOptions.h"
 #include "clang/Basic/CodeGenOptions.h"
 #include "clang/Basic/LLVM.h"
@@ -1009,11 +1010,11 @@ class TargetInfo : public TransferrableTargetInfo,
   virtual void getTargetDefines(const LangOptions &Opts,
                                 MacroBuilder &Builder) const = 0;
 
-
-  /// Return information about target-specific builtins for
-  /// the current primary target, and info about which builtins are non-portable
-  /// across the current set of primary and secondary targets.
-  virtual ArrayRef getTargetBuiltins() const = 0;
+  /// Return information about target-specific builtins for the current primary
+  /// target, and info about which builtins are non-portable across the current
+  /// set of primary and secondary targets.
+  virtual std::pair>
+  getTargetBuiltinStorage() const = 0;
 
   /// Returns target-specific min and max values VScale_Range.
   virtual std::optional>
@@ -1525,14 +1526,10 @@ class TargetInfo : public TransferrableTargetInfo,
 
   // Return the target-specific priority for features/cpus/vendors so
   // that they can be properly sorted for checking.
-  virtual unsigned multiVersionSortPriority(StringRef Name) const {
+  virtual unsigned getFMVPriority(ArrayRef Features) const {
     return 0;
   }
 
-  // Return the target-specific cost for feature
-  // that taken into account in priority sorting.
-  virtual unsigned multiVersionFeatureCost() const { return 0; }
-
   // Validate the contents of the __builtin_cpu_is(const char*)
   // argument.
   virtual bool validateCpuIs(StringRef Name) const { return false; }
diff --git a/clang/include/clang/Basic/arm_mve.td b/clang/include/clang/Basic/arm_mve.td
index 93abbc47c54dd..6dd8c52ddfd77 100644
--- a/clang/include/clang/Basic/arm_mve.td
+++ b/clang/include/clang/Basic/arm_mve.td
@@ -1270,13 +1270,13 @@ defm sqrshr: ScalarSaturatingShiftReg;
 def lsll: LongScalarShift $lo, $hi, $sh)>;
 def asrl: LongScalarShift $lo, $hi, $sh)>;
 
-multiclass vadcsbc {
+multiclass vadcsbc {
   def q: Intrinsic:$carry),
       (seq (IRInt $a, $b, (shl (load $carry), 29)):$pair,
            (store (and 1, (lshr (xval $pair, 1), 29)), $carry),
            (xval $pair, 0))>;
   def iq: Intrinsic:$carry),
-      (seq (IRInt $a, $b, 0):$pair,
+      (seq (IRInt $a, $b, initial_carry_in):$pair,
            (store (and 1, (lshr (xval $pair, 1), 29)), $carry),
            (xval $pair, 0))>;
   def q_m: Intrinsic:$carry, Predicate:$pred),
       (seq (IRInt $inactive, $a, $b,
-               0, $pred):$pair,
+               initial_carry_in, $pred):$pair,
            (store (and 1, (lshr (xval $pair, 1), 29)), $carry),
            (xval $pair, 0))>;
 }
 let params = T.Int32 in {
-  defm vadc: vadcsbc;
-  defm vsbc: vadcsbc;
+  defm vadc: vadcsbc<(u32 0)>;
+  defm vsbc: vadcsbc<(shl 1, 29)>;
 }
 
 let params = T.Int in {
diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td
index 0f689e82bdb74..71b2c7cdd04f9 100644
--- a/clang/include/clang/Basic/arm_sme.td
+++ b/clang/include/clang/Basic/arm_sme.td
@@ -824,4 +824,14 @@ let SMETargetGuard = "sme-lutv2" in {
   def SVLUTI4_ZT_X4 : SInst<"svluti4_zt_{d}_x4", "4i2.u", "cUc", MergeNone, "aarch64_sme_luti4_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>]>;
 }
 
+let SMETargetGuard = "sme-f8f32" in {
+  def SVMOPA_FP8_ZA32 : Inst<"svmopa_za32[_mf8]_m_fpm", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za32",
+                             [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<0, ImmCheck0_3>]>;
+}
+
+let SMETargetGuard = "sme-f8f16" in {
+  def SVMOPA_FP8_ZA16 : Inst<"svmopa_za16[_mf8]_m_fpm", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za16",
+                             [IsStreaming, IsInOutZA, SetsFPMR, IsOverloadNone], [ImmCheck<0, ImmCheck0_1>]>;
+}
+
 } // let SVETargetGuard = InvalidMode
diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index c6b7cd637b9ec..7b8ecf29a9de6 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone,
 ////////////////////////////////////////////////////////////////////////////////
 // While comparisons
 
-def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl",     MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl",     MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl",     MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl",     MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Counting bit
@@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl",     MergeNon
 def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl",     MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
 def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl",     MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
 def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl",     MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
-def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
+def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
 }
 
 let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2"  in {
@@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in {
 // Multi-vector convert to/from floating-point.
 //
 let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
-  def SVCVT_F16_X2  : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
+  def SVCVT_F16_X2  : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
   def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;
 
   def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f",  MergeNone, "aarch64_sve_ucvtf_x2",  [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
@@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in {
 // Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
 //
 let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
-  def SVCVTN_F16_X2  : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
+  def SVCVTN_F16_X2  : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
   def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
 }
 
@@ -2422,14 +2422,20 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
   def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>;
 }
 
-//
-// Multi-vector scaling
-//
-let  SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
+let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
+  // Multi-vector scaling
   def FSCALE_SINGLE_X2 : Inst<"svscale[_single_{d}_x2]", "22x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x2", [IsStreaming],[]>;
   def FSCALE_SINGLE_X4 : Inst<"svscale[_single_{d}_x4]", "44x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x4", [IsStreaming],[]>;
   def FSCALE_X2 : Inst<"svscale[_{d}_x2]", "222.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x2", [IsStreaming],[]>;
   def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x4", [IsStreaming],[]>;
+
+  // Convert from FP8 to half-precision/BFloat16 multi-vector
+  def SVF1CVT_X2 : Inst<"svcvt1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1_x2", [IsStreaming, SetsFPMR], []>;
+  def SVF2CVT_X2 : Inst<"svcvt2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2_x2", [IsStreaming, SetsFPMR], []>;
+
+  // Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector
+  def SVF1CVTL_X2 : Inst<"svcvtl1_{d}[_mf8]_x2_fpm",  "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2",  [IsStreaming, SetsFPMR], []>;
+  def SVF2CVTL_X2 : Inst<"svcvtl2_{d}[_mf8]_x2_fpm",  "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2",  [IsStreaming, SetsFPMR], []>;
 }
 
 let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
@@ -2445,3 +2451,15 @@ let SVETargetGuard = "sve2,faminmax", SMETargetGuard = "sme2,faminmax" in {
   defm SVAMIN : SInstZPZZ<"svamin", "hfd", "aarch64_sve_famin", "aarch64_sve_famin_u">;
   defm SVAMAX : SInstZPZZ<"svamax", "hfd", "aarch64_sve_famax", "aarch64_sve_famax_u">;
 }
+
+let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in {
+  // SVE FP8 widening conversions
+
+  // 8-bit floating-point convert to BFloat16/Float16
+  def SVF1CVT : SInst<"svcvt1_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1", [VerifyRuntimeMode, SetsFPMR]>;
+  def SVF2CVT : SInst<"svcvt2_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2", [VerifyRuntimeMode, SetsFPMR]>;
+
+  // 8-bit floating-point convert to BFloat16/Float16 (top)
+  def SVF1CVTLT : SInst<"svcvtlt1_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt1", [VerifyRuntimeMode, SetsFPMR]>;
+  def SVF2CVTLT : SInst<"svcvtlt2_{d}[_mf8]_fpm", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt2", [VerifyRuntimeMode, SetsFPMR]>;
+}
diff --git a/clang/include/clang/Basic/arm_sve_sme_incl.td b/clang/include/clang/Basic/arm_sve_sme_incl.td
index 50911fb63e818..de10be7bdce0d 100644
--- a/clang/include/clang/Basic/arm_sve_sme_incl.td
+++ b/clang/include/clang/Basic/arm_sve_sme_incl.td
@@ -94,6 +94,7 @@ include "arm_immcheck_incl.td"
 // l: int64_t
 // m: uint32_t
 // n: uint64_t
+// >: fpm_t
 
 // [: svuint8_t
 // t: svint32_t
@@ -103,6 +104,7 @@ include "arm_immcheck_incl.td"
 // M: svfloat32_t
 // N: svfloat64_t
 // $: svbfloat16_t
+// ~: svmfloat8_t
 
 // J: Prefetch type (sv_prfop)
 
@@ -235,6 +237,7 @@ def IsInOutZA                       : FlagType<0x200000000000>;
 def IsInZT0                         : FlagType<0x400000000000>;
 def IsOutZT0                        : FlagType<0x800000000000>;
 def IsInOutZT0                      : FlagType<0x1000000000000>;
+def SetsFPMR                        : FlagType<0x2000000000000>;
 
 defvar InvalidMode = "";
 
diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h
index c8ca7e4bfa728..414eba80b88b8 100644
--- a/clang/include/clang/CIR/CIRGenerator.h
+++ b/clang/include/clang/CIR/CIRGenerator.h
@@ -37,14 +37,14 @@ namespace cir {
 class CIRGenerator : public clang::ASTConsumer {
   virtual void anchor();
   clang::DiagnosticsEngine &diags;
-  clang::ASTContext *astCtx;
+  clang::ASTContext *astContext;
   // Only used for debug info.
   llvm::IntrusiveRefCntPtr fs;
 
   const clang::CodeGenOptions &codeGenOpts;
 
 protected:
-  std::unique_ptr mlirCtx;
+  std::unique_ptr mlirContext;
   std::unique_ptr cgm;
 
 public:
@@ -52,7 +52,7 @@ class CIRGenerator : public clang::ASTConsumer {
                llvm::IntrusiveRefCntPtr fs,
                const clang::CodeGenOptions &cgo);
   ~CIRGenerator() override;
-  void Initialize(clang::ASTContext &astCtx) override;
+  void Initialize(clang::ASTContext &astContext) override;
   bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
   mlir::ModuleOp getModule() const;
 };
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
new file mode 100644
index 0000000000000..75ae74e926fbc
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
+#define LLVM_CLANG_CIR_DIALECT_BUILDER_CIRBASEBUILDER_H
+
+#include "mlir/IR/Builders.h"
+
+namespace cir {
+
+class CIRBaseBuilderTy : public mlir::OpBuilder {
+
+public:
+  CIRBaseBuilderTy(mlir::MLIRContext &mlirContext)
+      : mlir::OpBuilder(&mlirContext) {}
+};
+
+} // namespace cir
+
+#endif
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4462eb6fc00ba..0d6c65ecf4102 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_CIR_DIALECT_IR_CIROPS
 
 include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "clang/CIR/Dialect/IR/CIRTypes.td"
 
 include "mlir/IR/BuiltinAttributeInterfaces.td"
 include "mlir/IR/EnumAttr.td"
@@ -74,6 +75,35 @@ class LLVMLoweringInfo {
 class CIR_Op traits = []> :
     Op, LLVMLoweringInfo;
 
+//===----------------------------------------------------------------------===//
+// GlobalOp
+//===----------------------------------------------------------------------===//
+
+// TODO(CIR): For starters, cir.global has only name and type.  The other
+// properties of a global variable will be added over time as more of ClangIR
+// is upstreamed.
+
+def GlobalOp : CIR_Op<"global"> {
+  let summary = "Declare or define a global variable";
+  let description = [{
+    The `cir.global` operation declares or defines a named global variable.
+
+    The backing memory for the variable is allocated statically and is
+    described by the type of the variable.
+  }];
+
+  let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type);
+
+  let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }];
+
+  let skipDefaultBuilders = 1;
+
+  let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name,
+                                 "mlir::Type":$sym_type)>];
+
+  let hasVerifier = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // FuncOp
 //===----------------------------------------------------------------------===//
@@ -85,14 +115,15 @@ class CIR_Op traits = []> :
 def FuncOp : CIR_Op<"func"> {
   let summary = "Declare or define a function";
   let description = [{
-    ... lots of text to be added later ...
+    The `cir.func` operation defines a function, similar to the `mlir::FuncOp`
+    built-in.
   }];
 
   let arguments = (ins SymbolNameAttr:$sym_name);
 
   let skipDefaultBuilders = 1;
 
-  let builders = [OpBuilder<(ins "llvm::StringRef":$name)>];
+  let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name)>];
 
   let hasCustomAssemblyFormat = 1;
   let hasVerifier = 1;
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.h b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
new file mode 100644
index 0000000000000..2bc7d77b2bc8a
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the types in the CIR dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_CIR_IR_CIRTYPES_H_
+#define MLIR_DIALECT_CIR_IR_CIRTYPES_H_
+
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/Types.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+
+//===----------------------------------------------------------------------===//
+// CIR Dialect Tablegen'd Types
+//===----------------------------------------------------------------------===//
+
+#define GET_TYPEDEF_CLASSES
+#include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc"
+
+#endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
new file mode 100644
index 0000000000000..ce0b6ba1d68c5
--- /dev/null
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -0,0 +1,132 @@
+//===- CIRTypes.td - CIR dialect types ---------------------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the CIR dialect types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CIR_DIALECT_CIR_TYPES
+#define MLIR_CIR_DIALECT_CIR_TYPES
+
+include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "mlir/Interfaces/DataLayoutInterfaces.td"
+include "mlir/IR/AttrTypeBase.td"
+
+//===----------------------------------------------------------------------===//
+// CIR Types
+//===----------------------------------------------------------------------===//
+
+class CIR_Type traits = [],
+               string baseCppClass = "::mlir::Type">
+    : TypeDef {
+  let mnemonic = typeMnemonic;
+}
+
+//===----------------------------------------------------------------------===//
+// IntType
+//===----------------------------------------------------------------------===//
+
+def CIR_IntType : CIR_Type<"Int", "int",
+    [DeclareTypeInterfaceMethods]> {
+  let summary = "Integer type with arbitrary precision up to a fixed limit";
+  let description = [{
+    CIR type that represents integer types with arbitrary precision, including
+    standard integral types such as `int` and `long`, extended integral types
+    such as `__int128`, and arbitrary width types such as `_BitInt(n)`.
+
+    Those integer types that are directly available in C/C++ standard are called
+    primitive integer types. Said types are: `signed char`, `short`, `int`,
+    `long`, `long long`, and their unsigned variations.
+  }];
+  let parameters = (ins "unsigned":$width, "bool":$isSigned);
+  let hasCustomAssemblyFormat = 1;
+  let extraClassDeclaration = [{
+    /// Return true if this is a signed integer type.
+    bool isSigned() const { return getIsSigned(); }
+    /// Return true if this is an unsigned integer type.
+    bool isUnsigned() const { return !getIsSigned(); }
+    /// Return type alias.
+    std::string getAlias() const {
+      return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
+    }
+    /// Return true if this is a primitive integer type (i.e. signed or unsigned
+    /// integer types whose bit width is 8, 16, 32, or 64).
+    bool isPrimitive() const {
+      return isValidPrimitiveIntBitwidth(getWidth());
+    }
+    bool isSignedPrimitive() const {
+      return isPrimitive() && isSigned();
+    }
+
+    /// Returns a minimum bitwidth of cir::IntType
+    static unsigned minBitwidth() { return 1; }
+    /// Returns a maximum bitwidth of cir::IntType
+    static unsigned maxBitwidth() { return 128; }
+
+    /// Returns true if cir::IntType that represents a primitive integer type
+    /// can be constructed from the provided bitwidth.
+    static bool isValidPrimitiveIntBitwidth(unsigned width) {
+      return width == 8 || width == 16 || width == 32 || width == 64;
+    }
+  }];
+  let genVerifyDecl = 1;
+}
+
+// Constraints
+
+// Unsigned integer type of a specific width.
+class UInt
+  : Type($_self)">,
+	CPred<"::mlir::cast<::cir::IntType>($_self).isUnsigned()">,
+	CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
+        ]>, width # "-bit unsigned integer", "::cir::IntType">,
+    BuildableType<
+      "cir::IntType::get($_builder.getContext(), "
+      # width # ", /*isSigned=*/false)"> {
+  int bitwidth = width;
+}
+
+def UInt1  : UInt<1>;
+def UInt8  : UInt<8>;
+def UInt16 : UInt<16>;
+def UInt32 : UInt<32>;
+def UInt64 : UInt<64>;
+
+// Signed integer type of a specific width.
+class SInt
+  : Type($_self)">,
+	CPred<"::mlir::cast<::cir::IntType>($_self).isSigned()">,
+	CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
+        ]>, width # "-bit signed integer", "::cir::IntType">,
+    BuildableType<
+      "cir::IntType::get($_builder.getContext(), "
+      # width # ", /*isSigned=*/true)"> {
+  int bitwidth = width;
+}
+
+def SInt1  : SInt<1>;
+def SInt8  : SInt<8>;
+def SInt16 : SInt<16>;
+def SInt32 : SInt<32>;
+def SInt64 : SInt<64>;
+
+def PrimitiveUInt
+    : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64], "primitive unsigned int",
+                "::cir::IntType">;
+
+def PrimitiveSInt
+    : AnyTypeOf<[SInt8, SInt16, SInt32, SInt64], "primitive signed int",
+                "::cir::IntType">;
+
+def PrimitiveInt
+    : AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64],
+                "primitive int", "::cir::IntType">;
+
+#endif // MLIR_CIR_DIALECT_CIR_TYPES
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 47d2f9b11bc0e..8ce7fca59445b 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -299,8 +299,11 @@ class Driver {
   /// Object that stores strings read from configuration file.
   llvm::StringSaver Saver;
 
-  /// Arguments originated from configuration file.
-  std::unique_ptr CfgOptions;
+  /// Arguments originated from configuration file (head part).
+  std::unique_ptr CfgOptionsHead;
+
+  /// Arguments originated from configuration file (tail part).
+  std::unique_ptr CfgOptionsTail;
 
   /// Arguments originated from command line.
   std::unique_ptr CLOptions;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1c72374133177..2f0af3739d63b 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -246,7 +246,8 @@ def m_riscv_Features_Group : OptionGroup<"">,
 def m_ve_Features_Group : OptionGroup<"">,
                           Group, DocName<"VE">;
 def m_loongarch_Features_Group : OptionGroup<"">,
-                                 Group, DocName<"LoongArch">;
+                                 Group, DocName<"LoongArch">,
+                                 Visibility<[ClangOption, CLOption, FlangOption]>;
 
 def m_libc_Group : OptionGroup<"">, Group,
                    Flags<[HelpHidden]>;
@@ -1808,7 +1809,7 @@ def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group;
 def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
     Group,
-    Visibility<[ClangOption, CC1Option]>,
+    Visibility<[ClangOption, CLOption, CC1Option]>,
     HelpText<"Enable sample-based profile guided optimizations">,
     MarshallingInfoString>;
 def fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">,
@@ -1858,12 +1859,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
   PosFlag,
   NegFlag>;
-def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">, 
+def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
     Group, Visibility<[ClangOption, CLOption]>,
     HelpText<"Generate instrumented code to collect coverage info for cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
-def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">, 
+def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
     Group, Visibility<[ClangOption, CLOption]>, MetaVarName<"">,
-    HelpText<"Generate instrumented code to collect coverage info for cold functions into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">; 
+    HelpText<"Generate instrumented code to collect coverage info for cold functions into /default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
 def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
     Group, Visibility<[ClangOption, CLOption]>,
     HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
@@ -3274,11 +3275,14 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
           "Perform ODR checks for decls in the global module fragment.">>,
   Group;
 
-def modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
+def modules_reduced_bmi : Flag<["-"], "fmodules-reduced-bmi">,
   Group, Visibility<[ClangOption, CC1Option]>,
   HelpText<"Generate the reduced BMI">,
   MarshallingInfoFlag>;
 
+def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, 
+  Group, Visibility<[ClangOption, CC1Option]>, Alias;
+
 def fmodules_embed_all_files : Joined<["-"], "fmodules-embed-all-files">,
   Visibility<[ClangOption, CC1Option, CLOption]>,
   HelpText<"Embed the contents of all files read by this compilation into "
@@ -4446,6 +4450,7 @@ defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of f
 defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini-address-discrimination",
   "Enable address discrimination of function pointers in init/fini arrays">;
 defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">;
+defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">;
 }
 
 def fenable_matrix : Flag<["-"], "fenable-matrix">, Group,
@@ -5193,6 +5198,10 @@ def matomics : Flag<["-"], "matomics">, Group;
 def mno_atomics : Flag<["-"], "mno-atomics">, Group;
 def mbulk_memory : Flag<["-"], "mbulk-memory">, Group;
 def mno_bulk_memory : Flag<["-"], "mno-bulk-memory">, Group;
+def mbulk_memory_opt : Flag<["-"], "mbulk-memory-opt">, Group;
+def mno_bulk_memory_opt : Flag<["-"], "mno-bulk-memory-opt">, Group;
+def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group;
+def mno_call_indirect_overlong : Flag<["-"], "mno-call-indirect-overlong">, Group;
 def mexception_handing : Flag<["-"], "mexception-handling">, Group;
 def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group;
 def mextended_const : Flag<["-"], "mextended-const">, Group;
@@ -5514,6 +5523,10 @@ def mlam_bh : Flag<["-"], "mlam-bh">, Group,
   HelpText<"Enable amswap[_db].{b/h} and amadd[_db].{b/h}">;
 def mno_lam_bh : Flag<["-"], "mno-lam-bh">, Group,
   HelpText<"Disable amswap[_db].{b/h} and amadd[_db].{b/h}">;
+def mlamcas : Flag<["-"], "mlamcas">, Group,
+  HelpText<"Enable amcas[_db].{b/h/w/d}">;
+def mno_lamcas : Flag<["-"], "mno-lamcas">, Group,
+  HelpText<"Disable amcas[_db].{b/h/w/d}">;
 def mld_seq_sa : Flag<["-"], "mld-seq-sa">, Group,
   HelpText<"Do not generate load-load barrier instructions (dbar 0x700)">;
 def mno_ld_seq_sa : Flag<["-"], "mno-ld-seq-sa">, Group,
@@ -7211,10 +7224,6 @@ def flang_deprecated_no_hlfir : Flag<["-"], "flang-deprecated-no-hlfir">,
   Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
   HelpText<"Do not use HLFIR lowering (deprecated)">;
 
-def flang_experimental_integer_overflow : Flag<["-"], "flang-experimental-integer-overflow">,
-  Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
-  HelpText<"Add nsw flag to internal operations such as do-variable increment (experimental)">;
-
 //===----------------------------------------------------------------------===//
 // FLangOption + Visibility<[FlangOption, CLOption, DXCOption] + NoXarchOption
 //===----------------------------------------------------------------------===//
@@ -7763,9 +7772,12 @@ def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfie
 def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
   HelpText<"Turn off Type Based Alias Analysis">,
   MarshallingInfoFlag>;
-def pointer_tbaa: Flag<["-"], "pointer-tbaa">,
-  HelpText<"Turn on Type Based Alias Analysis for pointer accesses">,
-  MarshallingInfoFlag>;
+defm pointer_tbaa: BoolOption<"", "pointer-tbaa", CodeGenOpts<"PointerTBAA">, 
+DefaultTrue,
+  PosFlag,
+  NegFlag,
+  BothFlags<[], [ClangOption], " that single precision floating-point divide and sqrt used in ">>
+  ;
 def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
   HelpText<"Turn off struct-path aware Type Based Alias Analysis">,
   MarshallingInfoNegativeFlag>;
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 056fad2cc0ff8..6383934afa2c4 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2506,9 +2506,9 @@ struct FormatStyle {
   /// lists.
   ///
   /// Important differences:
-  /// - No spaces inside the braced list.
-  /// - No line break before the closing brace.
-  /// - Indentation with the continuation indent, not with the block indent.
+  /// * No spaces inside the braced list.
+  /// * No line break before the closing brace.
+  /// * Indentation with the continuation indent, not with the block indent.
   ///
   /// Fundamentally, C++11 braced lists are formatted exactly like function
   /// calls would be formatted in their place. If the braced list follows a name
@@ -3742,19 +3742,19 @@ struct FormatStyle {
   QualifierAlignmentStyle QualifierAlignment;
 
   /// The order in which the qualifiers appear.
-  /// Order is an array that can contain any of the following:
+  /// The order is an array that can contain any of the following:
   ///
-  ///   * const
-  ///   * inline
-  ///   * static
-  ///   * friend
-  ///   * constexpr
-  ///   * volatile
-  ///   * restrict
-  ///   * type
+  ///   * ``const``
+  ///   * ``inline``
+  ///   * ``static``
+  ///   * ``friend``
+  ///   * ``constexpr``
+  ///   * ``volatile``
+  ///   * ``restrict``
+  ///   * ``type``
   ///
   /// \note
-  ///  It **must** contain ``type``.
+  ///  It must contain ``type``.
   /// \endnote
   ///
   /// Items to the left of ``type`` will be placed to the left of the type and
@@ -5449,10 +5449,10 @@ formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
 /// cleaning up the code after that on success; otherwise, return an llvm::Error
 /// carrying llvm::StringError.
 /// This also supports inserting/deleting C++ #include directives:
-/// - If a replacement has offset UINT_MAX, length 0, and a replacement text
+/// * If a replacement has offset UINT_MAX, length 0, and a replacement text
 ///   that is an #include directive, this will insert the #include into the
 ///   correct block in the \p Code.
-/// - If a replacement has offset UINT_MAX, length 1, and a replacement text
+/// * If a replacement has offset UINT_MAX, length 1, and a replacement text
 ///   that is the name of the header to be removed, the header will be removed
 ///   from \p Code if it exists.
 /// The include manipulation is done via ``tooling::HeaderInclude``, see its
@@ -5558,13 +5558,12 @@ extern const char *DefaultFallbackStyle;
 ///
 /// ``StyleName`` can take several forms:
 /// * "{: , ...}" - Set specic style parameters.
-/// * "